From 9c6aafd415369bef596e10e057a2d060f2f14f68 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 12 Nov 2024 17:32:39 +0800 Subject: [PATCH] feat: install bundle ui --- .../(commonLayout)/plugins/test/card/page.tsx | 32 +++---- web/app/components/plugins/card/card-mock.ts | 1 + .../install-plugin/install-bundle/index.tsx | 45 ++++++++-- .../install-bundle/steps/install.tsx | 85 +++++++++++++++++++ .../install-bundle/steps/select-package.tsx | 20 ----- .../components/plugins/plugin-item/index.tsx | 4 +- web/i18n/en-US/plugin.ts | 4 +- web/i18n/zh-Hans/plugin.ts | 4 +- 8 files changed, 148 insertions(+), 47 deletions(-) create mode 100644 web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx delete mode 100644 web/app/components/plugins/install-plugin/install-bundle/steps/select-package.tsx diff --git a/web/app/(commonLayout)/plugins/test/card/page.tsx b/web/app/(commonLayout)/plugins/test/card/page.tsx index dd280aac38..efc569a733 100644 --- a/web/app/(commonLayout)/plugins/test/card/page.tsx +++ b/web/app/(commonLayout)/plugins/test/card/page.tsx @@ -1,19 +1,21 @@ -import { handleDelete } from './actions' +'use client' import Card from '@/app/components/plugins/card' -import { customTool, extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock' -import PluginItem from '@/app/components/plugins/plugin-item' +import { customTool, extensionDallE, modelGPT4, toolNeko, toolNotion } from '@/app/components/plugins/card/card-mock' +// import PluginItem from '@/app/components/plugins/plugin-item' import CardMoreInfo from '@/app/components/plugins/card/card-more-info' -import ProviderCard from '@/app/components/plugins/provider-card' +// import ProviderCard from '@/app/components/plugins/provider-card' import Badge from '@/app/components/base/badge' +import InstallBundle from '@/app/components/plugins/install-plugin/install-bundle' -const PluginList = async () => { +const PluginList = () => { const pluginList = [toolNotion, extensionDallE, modelGPT4, customTool] return (
+ { }} plugins={[toolNeko, { ...toolNeko, plugin_unique_identifier: `${toolNeko.plugin_unique_identifier}xxx` }]} />
-

Dify Plugin list

-
+ {/*

Dify Plugin list

*/} + {/*
{pluginList.map((plugin, index) => ( { onDelete={handleDelete} /> ))} -
+
*/}

Install Plugin / Package under bundle

@@ -33,21 +35,21 @@ const PluginList = async () => { } />
-

Installed

+ {/*

Installed

-
+
*/} -

Install model provide

+ {/*

Install model provide

{pluginList.map((plugin, index) => ( ))} -
+
*/}

Marketplace Plugin list

@@ -67,8 +69,8 @@ const PluginList = async () => { ) } -export const metadata = { - title: 'Plugins - Card', -} +// export const metadata = { +// title: 'Plugins - Card', +// } export default PluginList diff --git a/web/app/components/plugins/card/card-mock.ts b/web/app/components/plugins/card/card-mock.ts index 4217c4d33a..201a7bc65d 100644 --- a/web/app/components/plugins/card/card-mock.ts +++ b/web/app/components/plugins/card/card-mock.ts @@ -2,6 +2,7 @@ import type { PluginDeclaration } from '../types' import { PluginType } from '../types' export const toolNeko: PluginDeclaration = { + plugin_unique_identifier: 'xxxxxx', version: '0.0.1', author: 'langgenius', name: 'neko', diff --git a/web/app/components/plugins/install-plugin/install-bundle/index.tsx b/web/app/components/plugins/install-plugin/install-bundle/index.tsx index 6086f0cbc3..6f20db7725 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/index.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/index.tsx @@ -1,9 +1,13 @@ 'use client' import type { FC } from 'react' -import React, { useState } from 'react' +import Modal from '@/app/components/base/modal' +import React, { useCallback, useState } from 'react' import { InstallStep } from '../../types' import type { PluginDeclaration } from '../../types' -import SelectPackage from './steps/select-package' +import Install from './steps/install' +import { useTranslation } from 'react-i18next' + +const i18nPrefix = 'plugin.installModal' export enum InstallType { fromLocal = 'fromLocal', @@ -14,24 +18,47 @@ export enum InstallType { type Props = { installType?: InstallType plugins?: PluginDeclaration[] + onClose: () => void } const InstallBundle: FC = ({ installType = InstallType.fromMarketplace, plugins = [], + onClose, }) => { + const { t } = useTranslation() const [step, setStep] = useState(installType === InstallType.fromMarketplace ? InstallStep.readyToInstall : InstallStep.uploading) - const [selectedPlugins, setSelectedPlugins] = useState([]) - const handleSelectedPluginsChange = (plugins: PluginDeclaration[]) => { - setSelectedPlugins(plugins) - } + const getTitle = useCallback(() => { + if (step === InstallStep.uploadFailed) + return t(`${i18nPrefix}.uploadFailed`) + if (step === InstallStep.installed) + return t(`${i18nPrefix}.installedSuccessfully`) + if (step === InstallStep.installFailed) + return t(`${i18nPrefix}.installFailed`) + + return t(`${i18nPrefix}.installPlugin`) + }, [step, t]) + return ( -
+ +
+
+ {getTitle()} +
+
{step === InstallStep.readyToInstall && ( - + )} -
+ ) } diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx new file mode 100644 index 0000000000..9b0e996f82 --- /dev/null +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx @@ -0,0 +1,85 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import type { PluginDeclaration } from '../../../types' +import Card from '../../../card' +import Button from '@/app/components/base/button' +import { RiLoader2Line } from '@remixicon/react' +import Badge, { BadgeState } from '@/app/components/base/badge/index' +import { pluginManifestToCardPluginProps } from '../../utils' +import { useTranslation } from 'react-i18next' +import Checkbox from '@/app/components/base/checkbox' + +const i18nPrefix = 'plugin.installModal' + +type Props = { + plugins: PluginDeclaration[], + onCancel: () => void +} + +const Install: FC = ({ + plugins, + onCancel, +}) => { + const { t } = useTranslation() + const [selectedPlugins, setSelectedPlugins] = React.useState([]) + const selectedPluginsNum = selectedPlugins.length + const handleSelect = (plugin: PluginDeclaration) => { + return () => { + const isSelected = !!selectedPlugins.find(p => p.plugin_unique_identifier === plugin.plugin_unique_identifier) + let nextSelectedPlugins + if (isSelected) + nextSelectedPlugins = selectedPlugins.filter(p => p.plugin_unique_identifier !== plugin.plugin_unique_identifier) + else + nextSelectedPlugins = [...selectedPlugins, plugin] + setSelectedPlugins(nextSelectedPlugins) + } + } + const [isInstalling, setIsInstalling] = React.useState(false) + const handleInstall = () => { + + } + return ( + <> +
+
+

{t(`${i18nPrefix}.${selectedPluginsNum > 1 ? 'readyToInstallPackages' : 'readyToInstallPackage'}`, { num: selectedPluginsNum })}

+
+
+ {plugins.map(plugin => ( +
+ p.plugin_unique_identifier === plugin.plugin_unique_identifier)} + onCheck={handleSelect(plugin)} + /> + {plugin.version}} + /> +
+ ))} +
+
+ {/* Action Buttons */} +
+ {!isInstalling && ( + + )} + +
+ + ) +} +export default React.memo(Install) diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/select-package.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/select-package.tsx deleted file mode 100644 index 70a51c265c..0000000000 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/select-package.tsx +++ /dev/null @@ -1,20 +0,0 @@ -'use client' -import type { FC } from 'react' -import React from 'react' -import type { PluginDeclaration } from '../../../types' - -type Props = { - plugins: PluginDeclaration[], - onChange: (plugins: PluginDeclaration[]) => void -} - -const SelectPackage: FC = ({ - plugins, - onChange, -}) => { - return ( -
-
- ) -} -export default React.memo(SelectPackage) diff --git a/web/app/components/plugins/plugin-item/index.tsx b/web/app/components/plugins/plugin-item/index.tsx index 5a6a3a6ca2..4ef0340641 100644 --- a/web/app/components/plugins/plugin-item/index.tsx +++ b/web/app/components/plugins/plugin-item/index.tsx @@ -61,7 +61,9 @@ const PluginItem: FC = ({ ? 'bg-[repeating-linear-gradient(-45deg,rgba(16,24,40,0.04),rgba(16,24,40,0.04)_5px,rgba(0,0,0,0.02)_5px,rgba(0,0,0,0.02)_10px)]' : 'bg-background-section-burn', )} - onClick={() => setCurrentPluginDetail(plugin)} + onClick={() => { + setCurrentPluginDetail(plugin) + }} >
diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts index abcf3480bb..689510acca 100644 --- a/web/i18n/en-US/plugin.ts +++ b/web/i18n/en-US/plugin.ts @@ -80,7 +80,9 @@ const translation = { install: 'Install', installing: 'Installing...', uploadingPackage: 'Uploading {{packageName}}...', - readyToInstall: 'About to install the following plugin.', + readyToInstall: 'About to install the following plugin', + readyToInstallPackage: 'About to install the following plugin', + readyToInstallPackages: 'About to install the following {{num}} plugins', fromTrustSource: 'Please make sure that you only install plugins from a trusted source.', labels: { repository: 'Repository', diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts index 3355cb742c..25cd0ba03f 100644 --- a/web/i18n/zh-Hans/plugin.ts +++ b/web/i18n/zh-Hans/plugin.ts @@ -80,7 +80,9 @@ const translation = { install: '安装', installing: '安装中...', uploadingPackage: '上传 {{packageName}} 中...', - readyToInstall: '即将安装以下插件。', + readyToInstall: '即将安装以下插件', + readyToInstallPackage: '即将安装以下插件', + readyToInstallPackages: '即将安装以下 {{num}} 个插件', fromTrustSource: '请保证仅从可信源安装插件。', labels: { repository: '仓库',