diff --git a/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx b/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx
index dce2e735c8..c046957263 100644
--- a/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx
+++ b/web/app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx
@@ -9,7 +9,7 @@ import { pluginManifestToCardPluginProps } from '../../utils'
import { useTranslation } from 'react-i18next'
import { installPackageFromGitHub, uninstallPlugin } from '@/service/plugins'
import { RiLoader2Line } from '@remixicon/react'
-import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/store'
+import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/plugin-tasks/store'
import checkTaskStatus from '../../base/check-task-status'
import { parseGitHubUrl } from '../../utils'
diff --git a/web/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx b/web/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx
index b48922bdb9..4d776f4430 100644
--- a/web/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx
+++ b/web/app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx
@@ -10,7 +10,7 @@ import { RiLoader2Line } from '@remixicon/react'
import Badge, { BadgeState } from '@/app/components/base/badge/index'
import { useInstallPackageFromLocal } from '@/service/use-plugins'
import checkTaskStatus from '../../base/check-task-status'
-import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/store'
+import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/plugin-tasks/store'
const i18nPrefix = 'plugin.installModal'
diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx
index f889bbc363..013c9bc9e2 100644
--- a/web/app/components/plugins/plugin-page/index.tsx
+++ b/web/app/components/plugins/plugin-page/index.tsx
@@ -16,8 +16,8 @@ import InstallPluginDropdown from './install-plugin-dropdown'
import { useUploader } from './use-uploader'
import usePermission from './use-permission'
import DebugInfo from './debug-info'
-import { usePluginTasksStore } from './store'
-import InstallInfo from './install-info'
+import { usePluginTasksStore } from './plugin-tasks/store'
+import PluginTasks from './plugin-tasks'
import Button from '@/app/components/base/button'
import TabSlider from '@/app/components/base/tab-slider'
import Tooltip from '@/app/components/base/tooltip'
@@ -102,8 +102,6 @@ const PluginPage = ({
const options = usePluginPageContext(v => v.options)
const [activeTab, setActiveTab] = usePluginPageContext(v => [v.activeTab, v.setActiveTab])
const { enable_marketplace } = useAppContextSelector(s => s.systemFeatures)
- const [installed, total] = [2, 3] // Replace this with the actual progress
- const progressPercentage = (installed / total) * 100
const uploaderProps = useUploader({
onFileChange: setCurrentFile,
@@ -142,7 +140,7 @@ const PluginPage = ({
/>
-
+
{canManagement && (
setActiveTab('discover')}
diff --git a/web/app/components/plugins/plugin-page/install-info.tsx b/web/app/components/plugins/plugin-page/install-info.tsx
deleted file mode 100644
index bb0a31f4be..0000000000
--- a/web/app/components/plugins/plugin-page/install-info.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import {
- useState,
-} from 'react'
-import {
- RiCheckboxCircleFill,
- RiErrorWarningFill,
- RiInstallLine,
-} from '@remixicon/react'
-import {
- PortalToFollowElem,
- PortalToFollowElemContent,
- PortalToFollowElemTrigger,
-} from '@/app/components/base/portal-to-follow-elem'
-import Tooltip from '@/app/components/base/tooltip'
-import Button from '@/app/components/base/button'
-// import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
-import { useMemo } from 'react'
-import cn from '@/utils/classnames'
-
-const InstallInfo = () => {
- const [open, setOpen] = useState(false)
- const status = 'error'
- const statusError = useMemo(() => status === 'error', [status])
-
- return (
-
-
- setOpen(v => !v)}>
-
-
-
-
-
-
-
3 plugins failed to install
-
-
-
-
-
- DuckDuckGo Search
-
-
-
-
-
-
-
- )
-}
-
-export default InstallInfo
diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts b/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts
new file mode 100644
index 0000000000..3a198f5068
--- /dev/null
+++ b/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts
@@ -0,0 +1,27 @@
+import { usePluginTasksStore } from './store'
+import { TaskStatus } from '@/app/components/plugins/types'
+import type { PluginStatus } from '@/app/components/plugins/types'
+
+export const usePluginTaskStatus = () => {
+ const pluginTasks = usePluginTasksStore(s => s.pluginTasks)
+ const allPlugins = pluginTasks.map(task => task.plugins).flat()
+ const errorPlugins: PluginStatus[] = []
+ const successPlugins: PluginStatus[] = []
+ const runningPlugins: PluginStatus[] = []
+
+ allPlugins.forEach((plugin) => {
+ if (plugin.status === TaskStatus.running)
+ runningPlugins.push(plugin)
+ if (plugin.status === TaskStatus.failed)
+ errorPlugins.push(plugin)
+ if (plugin.status === TaskStatus.success)
+ successPlugins.push(plugin)
+ })
+
+ return {
+ errorPlugins,
+ successPlugins,
+ runningPlugins,
+ totalPluginsLength: allPlugins.length,
+ }
+}
diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx
new file mode 100644
index 0000000000..bde4371839
--- /dev/null
+++ b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx
@@ -0,0 +1,137 @@
+import {
+ useMemo,
+ useState,
+} from 'react'
+import {
+ RiCheckboxCircleFill,
+ RiErrorWarningFill,
+ RiInstallLine,
+} from '@remixicon/react'
+import { useTranslation } from 'react-i18next'
+import { usePluginTaskStatus } from './hooks'
+import {
+ PortalToFollowElem,
+ PortalToFollowElemContent,
+ PortalToFollowElemTrigger,
+} from '@/app/components/base/portal-to-follow-elem'
+import Tooltip from '@/app/components/base/tooltip'
+import Button from '@/app/components/base/button'
+import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
+import cn from '@/utils/classnames'
+
+const PluginTasks = () => {
+ const { t } = useTranslation()
+ const [open, setOpen] = useState(false)
+ const {
+ errorPlugins,
+ runningPlugins,
+ successPlugins,
+ totalPluginsLength,
+ } = usePluginTaskStatus()
+
+ const isInstalling = runningPlugins.length > 0 && errorPlugins.length === 0 && successPlugins.length === 0
+ const isInstallingWithError = errorPlugins.length > 0 && errorPlugins.length < totalPluginsLength
+ const isSuccess = successPlugins.length === totalPluginsLength && totalPluginsLength > 0
+ const isFailed = errorPlugins.length === totalPluginsLength && totalPluginsLength > 0
+
+ const tip = useMemo(() => {
+ if (isInstalling)
+ return t('plugin.task.installing', { installingLength: runningPlugins.length, totalLength: totalPluginsLength })
+
+ if (isInstallingWithError)
+ return t('plugin.task.installingWithError', { installingLength: runningPlugins.length, totalLength: totalPluginsLength, errorLength: errorPlugins.length })
+
+ if (isFailed)
+ return t('plugin.task.installError', { errorLength: errorPlugins.length })
+ }, [isInstalling, isInstallingWithError, isFailed, errorPlugins, runningPlugins, totalPluginsLength, t])
+
+ return (
+
+
+ {
+ if (isFailed || isInstallingWithError)
+ setOpen(v => !v)
+ }}
+ >
+
+
+
+
+ {
+ isInstalling && (
+
+ )
+ }
+ {
+ isInstallingWithError && (
+
+ )
+ }
+ {
+ isSuccess && (
+
+ )
+ }
+ {
+ isFailed && (
+
+ )
+ }
+
+
+
+
+
+
+
{t('plugin.task.installedError')}
+
+
+
+
+
+ DuckDuckGo Search
+
+
+
+
+
+
+
+ )
+}
+
+export default PluginTasks
diff --git a/web/app/components/plugins/plugin-page/store.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/store.ts
similarity index 94%
rename from web/app/components/plugins/plugin-page/store.tsx
rename to web/app/components/plugins/plugin-page/plugin-tasks/store.ts
index 25074b973f..403d529a39 100644
--- a/web/app/components/plugins/plugin-page/store.tsx
+++ b/web/app/components/plugins/plugin-page/plugin-tasks/store.ts
@@ -1,5 +1,5 @@
import { create } from 'zustand'
-import type { PluginTask } from '../types'
+import type { PluginTask } from '@/app/components/plugins/types'
import { fetchPluginTasks } from '@/service/plugins'
type PluginTasksStore = {
diff --git a/web/app/components/plugins/update-plugin/from-market-place.tsx b/web/app/components/plugins/update-plugin/from-market-place.tsx
index e0b54a1acf..0454617a2e 100644
--- a/web/app/components/plugins/update-plugin/from-market-place.tsx
+++ b/web/app/components/plugins/update-plugin/from-market-place.tsx
@@ -12,7 +12,7 @@ import { pluginManifestToCardPluginProps } from '@/app/components/plugins/instal
import useGetIcon from '../install-plugin/base/use-get-icon'
import { updateFromMarketPlace } from '@/service/plugins'
import checkTaskStatus from '@/app/components/plugins/install-plugin/base/check-task-status'
-import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/store'
+import { usePluginTasksStore } from '@/app/components/plugins/plugin-page/plugin-tasks/store'
const i18nPrefix = 'plugin.upgrade'
diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts
index 5c3bdc6f29..abcf3480bb 100644
--- a/web/i18n/en-US/plugin.ts
+++ b/web/i18n/en-US/plugin.ts
@@ -124,6 +124,12 @@ const translation = {
inDifyMarketplace: 'in Dify Marketplace',
moreFrom: 'More from Marketplace',
},
+ task: {
+ installing: 'Installing {{installingLength}}/{{totalLength}} plugins...',
+ installingWithError: 'Installing {{installingLength}} of {{totalLength}} plugins, {{errorLength}} failed, click to view',
+ installError: '{{errorLength}} plugins failed to install, click to view',
+ installedError: '{{errorLength}} plugins failed to install',
+ },
}
export default translation
diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts
index c1f7bb7600..3355cb742c 100644
--- a/web/i18n/zh-Hans/plugin.ts
+++ b/web/i18n/zh-Hans/plugin.ts
@@ -124,6 +124,12 @@ const translation = {
inDifyMarketplace: '在 Dify 市场中',
moreFrom: '更多来自市场',
},
+ task: {
+ installing: '{{installingLength}}/{{totalLength}} 插件安装中...',
+ installingWithError: '{{installingLength}}/{{totalLength}} 插件安装中,{{errorLength}} 安装失败。点击查看',
+ installError: '{{errorLength}} 个插件安装失败,点击查看',
+ installedError: '{{errorLength}} 个插件安装失败',
+ },
}
export default translation