From 13d3f67746bc4cbca3c2d27ae427aea61fe418c2 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Tue, 12 Nov 2024 17:58:14 +0800 Subject: [PATCH] feat: plugin task use query --- .../install-from-github/steps/loaded.tsx | 6 +-- .../steps/install.tsx | 6 +-- .../components/plugins/plugin-page/index.tsx | 7 --- .../plugins/plugin-page/plugin-tasks/hooks.ts | 26 +++++++++-- .../plugin-page/plugin-tasks/index.tsx | 43 +++++++++++------ .../plugins/plugin-page/plugin-tasks/store.ts | 40 ---------------- web/app/components/plugins/types.ts | 3 ++ .../update-plugin/from-market-place.tsx | 8 ++-- web/service/use-plugins.ts | 46 +++++++++++++++++++ 9 files changed, 111 insertions(+), 74 deletions(-) delete mode 100644 web/app/components/plugins/plugin-page/plugin-tasks/store.ts 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 c046957263..2311cb781e 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/plugin-tasks/store' +import { usePluginTaskList } from '@/service/use-plugins' import checkTaskStatus from '../../base/check-task-status' import { parseGitHubUrl } from '../../utils' @@ -40,7 +40,7 @@ const Loaded: React.FC = ({ }) => { const { t } = useTranslation() const [isInstalling, setIsInstalling] = React.useState(false) - const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) + const { handleRefetch } = usePluginTaskList() const { check } = checkTaskStatus() const handleInstall = async () => { @@ -64,7 +64,7 @@ const Loaded: React.FC = ({ return } - setPluginTasksWithPolling() + handleRefetch() await check({ taskId, pluginUniqueIdentifier: uniqueIdentifier, 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 4d776f4430..43c2a03319 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/plugin-tasks/store' +import { usePluginTaskList } from '@/service/use-plugins' const i18nPrefix = 'plugin.installModal' @@ -45,7 +45,7 @@ const Installed: FC = ({ onCancel() } - const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) + const { handleRefetch } = usePluginTaskList() const handleInstall = async () => { if (isInstalling) return setIsInstalling(true) @@ -60,7 +60,7 @@ const Installed: FC = ({ onInstalled() return } - setPluginTasksWithPolling() + handleRefetch() await check({ taskId, pluginUniqueIdentifier: uniqueIdentifier, diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx index 013c9bc9e2..2cba8cf939 100644 --- a/web/app/components/plugins/plugin-page/index.tsx +++ b/web/app/components/plugins/plugin-page/index.tsx @@ -16,7 +16,6 @@ import InstallPluginDropdown from './install-plugin-dropdown' import { useUploader } from './use-uploader' import usePermission from './use-permission' import DebugInfo from './debug-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' @@ -111,12 +110,6 @@ const PluginPage = ({ const { dragging, fileUploader, fileChangeHandle, removeFile } = uploaderProps - const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) - - useEffect(() => { - setPluginTasksWithPolling() - }, [setPluginTasksWithPolling]) - return (
{ - const pluginTasks = usePluginTasksStore(s => s.pluginTasks) - const allPlugins = pluginTasks.map(task => task.plugins).flat() + const { + pluginTasks, + } = usePluginTaskList() + const { mutate } = useMutationClearTaskPlugin() + const allPlugins = pluginTasks.map(task => task.plugins.map((plugin) => { + return { + ...plugin, + taskId: task.id, + } + })).flat() const errorPlugins: PluginStatus[] = [] const successPlugins: PluginStatus[] = [] const runningPlugins: PluginStatus[] = [] @@ -18,10 +30,18 @@ export const usePluginTaskStatus = () => { successPlugins.push(plugin) }) + const handleClearErrorPlugin = useCallback((taskId: string, pluginId: string) => { + mutate({ + taskId, + pluginId, + }) + }, [mutate]) + return { errorPlugins, successPlugins, runningPlugins, totalPluginsLength: allPlugins.length, + handleClearErrorPlugin, } } diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx index bde4371839..ebf2db44b6 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx +++ b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx @@ -17,16 +17,20 @@ import { 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 CardIcon from '@/app/components/plugins/card/base/card-icon' import cn from '@/utils/classnames' +import { useGetLanguage } from '@/context/i18n' const PluginTasks = () => { const { t } = useTranslation() + const language = useGetLanguage() const [open, setOpen] = useState(false) const { errorPlugins, runningPlugins, successPlugins, totalPluginsLength, + handleClearErrorPlugin, } = usePluginTaskStatus() const isInstalling = runningPlugins.length > 0 && errorPlugins.length === 0 && successPlugins.length === 0 @@ -113,20 +117,31 @@ const PluginTasks = () => {
{t('plugin.task.installedError')}
-
-
- -
-
- DuckDuckGo Search -
- -
+ { + errorPlugins.map(errorPlugin => ( +
+
+ + +
+
+ {errorPlugin.labels[language]} +
+ +
+ )) + }
diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/store.ts b/web/app/components/plugins/plugin-page/plugin-tasks/store.ts deleted file mode 100644 index 403d529a39..0000000000 --- a/web/app/components/plugins/plugin-page/plugin-tasks/store.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { create } from 'zustand' -import type { PluginTask } from '@/app/components/plugins/types' -import { fetchPluginTasks } from '@/service/plugins' - -type PluginTasksStore = { - pluginTasks: PluginTask[] - setPluginTasks: (tasks: PluginTask[]) => void - setPluginTasksWithPolling: () => void -} - -let pluginTasksTimer: NodeJS.Timeout | null = null - -export const usePluginTasksStore = create(set => ({ - pluginTasks: [], - setPluginTasks: (tasks: PluginTask[]) => set({ pluginTasks: tasks }), - setPluginTasksWithPolling: async () => { - if (pluginTasksTimer) { - clearTimeout(pluginTasksTimer) - pluginTasksTimer = null - } - const handleUpdatePluginTasks = async () => { - const { tasks } = await fetchPluginTasks() - set({ pluginTasks: tasks }) - - if (tasks.length && !tasks.every(task => task.status === 'success')) { - pluginTasksTimer = setTimeout(() => { - handleUpdatePluginTasks() - }, 5000) - } - else { - if (pluginTasksTimer) { - clearTimeout(pluginTasksTimer) - pluginTasksTimer = null - } - } - } - - handleUpdatePluginTasks() - }, -})) diff --git a/web/app/components/plugins/types.ts b/web/app/components/plugins/types.ts index a869b2c556..1554c56097 100644 --- a/web/app/components/plugins/types.ts +++ b/web/app/components/plugins/types.ts @@ -260,6 +260,9 @@ export type PluginStatus = { plugin_id: string status: TaskStatus message: string + icon: string + labels: Record + taskId: string } export type PluginTask = { 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 c76b154c40..20dfc294a7 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/plugin-tasks/store' +import { usePluginTaskList } from '@/service/use-plugins' const i18nPrefix = 'plugin.upgrade' @@ -56,7 +56,7 @@ const UpdatePluginModal: FC = ({ } const [uploadStep, setUploadStep] = useState(UploadStep.notStarted) - const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) + const { handleRefetch } = usePluginTaskList() const configBtnText = useMemo(() => { return ({ @@ -82,7 +82,7 @@ const UpdatePluginModal: FC = ({ onSave() return } - setPluginTasksWithPolling() + handleRefetch() await check({ taskId, pluginUniqueIdentifier: targetPackageInfo.id, @@ -98,7 +98,7 @@ const UpdatePluginModal: FC = ({ onSave() onCancel() } - }, [onCancel, onSave, uploadStep, check, originalPackageInfo.id, setPluginTasksWithPolling, targetPackageInfo.id]) + }, [onCancel, onSave, uploadStep, check, originalPackageInfo.id, handleRefetch, targetPackageInfo.id]) const usedInAppInfo = useMemo(() => { return (
diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 3b72bee919..33abac865d 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -1,8 +1,10 @@ +import { useCallback, useState } from 'react' import type { DebugInfo as DebugInfoTypes, InstallPackageResponse, InstalledPluginListResponse, Permissions, + PluginTask, PluginsFromMarketplaceResponse, } from '@/app/components/plugins/types' import type { @@ -115,3 +117,47 @@ export const useMutationPluginsFromMarketplace = () => { }, }) } + +const usePluginTaskListKey = [NAME_SPACE, 'pluginTaskList'] +export const usePluginTaskList = () => { + const [enabled, setEnabled] = useState(true) + const { + data, + isFetched, + refetch, + ...rest + } = useQuery({ + queryKey: usePluginTaskListKey, + queryFn: async () => { + const currentData = await get<{ tasks: PluginTask[] }>('/workspaces/current/plugin/tasks?page=1&page_size=100') + const taskDone = currentData.tasks.every(task => task.total_plugins === task.completed_plugins) + + if (taskDone) + setEnabled(false) + + return currentData + }, + refetchInterval: 5000, + enabled, + }) + const handleRefetch = useCallback(() => { + setEnabled(true) + refetch() + }, [refetch]) + + return { + data, + pluginTasks: data?.tasks || [], + isFetched, + handleRefetch, + ...rest, + } +} + +export const useMutationClearTaskPlugin = () => { + return useMutation({ + mutationFn: ({ taskId, pluginId }: { taskId: string; pluginId: string }) => { + return post<{ success: boolean }>(`/workspaces/current/plugin/task/${taskId}/delete/${pluginId}`) + }, + }) +}