Files
dify/web/app/components/tools/plugin-category-page.tsx
2026-05-13 11:23:35 -07:00

101 lines
3.3 KiB
TypeScript

'use client'
import type { ReactNode } from 'react'
import { useSuspenseQuery } from '@tanstack/react-query'
import { noop } from 'es-toolkit/function'
import { useMemo, useState } from 'react'
import InstallFromLocalPackage from '@/app/components/plugins/install-plugin/install-from-local-package'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import { PluginPageContextProvider } from '@/app/components/plugins/plugin-page/context-provider'
import PluginsPanel from '@/app/components/plugins/plugin-page/plugins-panel'
import { useUploader } from '@/app/components/plugins/plugin-page/use-uploader'
import { PluginCategoryEnum } from '@/app/components/plugins/types'
import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config'
import { systemFeaturesQueryOptions } from '@/service/system-features'
type PluginCategoryPageProps = {
category: PluginCategoryEnum
toolbarAction?: ReactNode
}
const supportedLocalPackageExtensions = SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS.split(',')
const PluginCategoryPageContent = ({
category,
toolbarAction,
}: PluginCategoryPageProps) => {
const [currentFile, setCurrentFile] = useState<File | null>(null)
const containerRef = usePluginPageContext(v => v.containerRef)
const { data: pluginInstallationPermission } = useSuspenseQuery({
...systemFeaturesQueryOptions(),
select: s => s.plugin_installation_permission,
})
const supportsDropInstall = category === PluginCategoryEnum.trigger || category === PluginCategoryEnum.agent
const canDropLocalPackage = supportsDropInstall && !pluginInstallationPermission.restrict_to_marketplace_only
const handleFileChange = (file: File | null) => {
if (!file || !supportedLocalPackageExtensions.some(extension => file.name.endsWith(extension))) {
setCurrentFile(null)
return
}
setCurrentFile(file)
}
const {
dragging,
fileUploader,
fileChangeHandle,
removeFile,
} = useUploader({
onFileChange: handleFileChange,
containerRef,
enabled: canDropLocalPackage,
})
return (
<div ref={containerRef} className="relative flex h-0 grow flex-col overflow-hidden bg-background-body">
<PluginsPanel contentInset="compact" fixedCategory={category} toolbarAction={toolbarAction} />
{dragging && (
<div
className="absolute inset-0 m-0.5 rounded-2xl border-2 border-dashed border-components-dropzone-border-accent
bg-[rgba(21,90,239,0.14)] p-2"
/>
)}
{currentFile && (
<InstallFromLocalPackage
file={currentFile}
onClose={removeFile ?? noop}
onSuccess={noop}
/>
)}
<input
ref={fileUploader}
className="hidden"
type="file"
id="fileUploader"
accept={SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS}
onChange={fileChangeHandle ?? noop}
/>
</div>
)
}
const PluginCategoryPage = ({
category,
toolbarAction,
}: PluginCategoryPageProps) => {
const initialFilters = useMemo(() => ({
categories: [category],
tags: [],
searchQuery: '',
}), [category])
return (
<PluginPageContextProvider key={category} initialFilters={initialFilters}>
<PluginCategoryPageContent category={category} toolbarAction={toolbarAction} />
</PluginPageContextProvider>
)
}
export default PluginCategoryPage