feat: plugin task use query

pull/12372/head
StyleZhang 1 year ago
parent 9c6aafd415
commit 13d3f67746

@ -9,7 +9,7 @@ import { pluginManifestToCardPluginProps } from '../../utils'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { installPackageFromGitHub, uninstallPlugin } from '@/service/plugins' import { installPackageFromGitHub, uninstallPlugin } from '@/service/plugins'
import { RiLoader2Line } from '@remixicon/react' 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 checkTaskStatus from '../../base/check-task-status'
import { parseGitHubUrl } from '../../utils' import { parseGitHubUrl } from '../../utils'
@ -40,7 +40,7 @@ const Loaded: React.FC<LoadedProps> = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isInstalling, setIsInstalling] = React.useState(false) const [isInstalling, setIsInstalling] = React.useState(false)
const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) const { handleRefetch } = usePluginTaskList()
const { check } = checkTaskStatus() const { check } = checkTaskStatus()
const handleInstall = async () => { const handleInstall = async () => {
@ -64,7 +64,7 @@ const Loaded: React.FC<LoadedProps> = ({
return return
} }
setPluginTasksWithPolling() handleRefetch()
await check({ await check({
taskId, taskId,
pluginUniqueIdentifier: uniqueIdentifier, pluginUniqueIdentifier: uniqueIdentifier,

@ -10,7 +10,7 @@ import { RiLoader2Line } from '@remixicon/react'
import Badge, { BadgeState } from '@/app/components/base/badge/index' import Badge, { BadgeState } from '@/app/components/base/badge/index'
import { useInstallPackageFromLocal } from '@/service/use-plugins' import { useInstallPackageFromLocal } from '@/service/use-plugins'
import checkTaskStatus from '../../base/check-task-status' 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' const i18nPrefix = 'plugin.installModal'
@ -45,7 +45,7 @@ const Installed: FC<Props> = ({
onCancel() onCancel()
} }
const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) const { handleRefetch } = usePluginTaskList()
const handleInstall = async () => { const handleInstall = async () => {
if (isInstalling) return if (isInstalling) return
setIsInstalling(true) setIsInstalling(true)
@ -60,7 +60,7 @@ const Installed: FC<Props> = ({
onInstalled() onInstalled()
return return
} }
setPluginTasksWithPolling() handleRefetch()
await check({ await check({
taskId, taskId,
pluginUniqueIdentifier: uniqueIdentifier, pluginUniqueIdentifier: uniqueIdentifier,

@ -16,7 +16,6 @@ import InstallPluginDropdown from './install-plugin-dropdown'
import { useUploader } from './use-uploader' import { useUploader } from './use-uploader'
import usePermission from './use-permission' import usePermission from './use-permission'
import DebugInfo from './debug-info' import DebugInfo from './debug-info'
import { usePluginTasksStore } from './plugin-tasks/store'
import PluginTasks from './plugin-tasks' import PluginTasks from './plugin-tasks'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import TabSlider from '@/app/components/base/tab-slider' import TabSlider from '@/app/components/base/tab-slider'
@ -111,12 +110,6 @@ const PluginPage = ({
const { dragging, fileUploader, fileChangeHandle, removeFile } = uploaderProps const { dragging, fileUploader, fileChangeHandle, removeFile } = uploaderProps
const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling)
useEffect(() => {
setPluginTasksWithPolling()
}, [setPluginTasksWithPolling])
return ( return (
<div <div
id='marketplace-container' id='marketplace-container'

@ -1,10 +1,22 @@
import { usePluginTasksStore } from './store' import { useCallback } from 'react'
import { TaskStatus } from '@/app/components/plugins/types' import { TaskStatus } from '@/app/components/plugins/types'
import type { PluginStatus } from '@/app/components/plugins/types' import type { PluginStatus } from '@/app/components/plugins/types'
import {
useMutationClearTaskPlugin,
usePluginTaskList,
} from '@/service/use-plugins'
export const usePluginTaskStatus = () => { export const usePluginTaskStatus = () => {
const pluginTasks = usePluginTasksStore(s => s.pluginTasks) const {
const allPlugins = pluginTasks.map(task => task.plugins).flat() pluginTasks,
} = usePluginTaskList()
const { mutate } = useMutationClearTaskPlugin()
const allPlugins = pluginTasks.map(task => task.plugins.map((plugin) => {
return {
...plugin,
taskId: task.id,
}
})).flat()
const errorPlugins: PluginStatus[] = [] const errorPlugins: PluginStatus[] = []
const successPlugins: PluginStatus[] = [] const successPlugins: PluginStatus[] = []
const runningPlugins: PluginStatus[] = [] const runningPlugins: PluginStatus[] = []
@ -18,10 +30,18 @@ export const usePluginTaskStatus = () => {
successPlugins.push(plugin) successPlugins.push(plugin)
}) })
const handleClearErrorPlugin = useCallback((taskId: string, pluginId: string) => {
mutate({
taskId,
pluginId,
})
}, [mutate])
return { return {
errorPlugins, errorPlugins,
successPlugins, successPlugins,
runningPlugins, runningPlugins,
totalPluginsLength: allPlugins.length, totalPluginsLength: allPlugins.length,
handleClearErrorPlugin,
} }
} }

@ -17,16 +17,20 @@ import {
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import ProgressCircle from '@/app/components/base/progress-bar/progress-circle' 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 cn from '@/utils/classnames'
import { useGetLanguage } from '@/context/i18n'
const PluginTasks = () => { const PluginTasks = () => {
const { t } = useTranslation() const { t } = useTranslation()
const language = useGetLanguage()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const { const {
errorPlugins, errorPlugins,
runningPlugins, runningPlugins,
successPlugins, successPlugins,
totalPluginsLength, totalPluginsLength,
handleClearErrorPlugin,
} = usePluginTaskStatus() } = usePluginTaskStatus()
const isInstalling = runningPlugins.length > 0 && errorPlugins.length === 0 && successPlugins.length === 0 const isInstalling = runningPlugins.length > 0 && errorPlugins.length === 0 && successPlugins.length === 0
@ -113,20 +117,31 @@ const PluginTasks = () => {
<PortalToFollowElemContent className='z-10'> <PortalToFollowElemContent className='z-10'>
<div className='p-1 pb-2 w-[320px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'> <div className='p-1 pb-2 w-[320px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
<div className='flex items-center px-2 pt-1 h-7 system-sm-semibold-uppercase'>{t('plugin.task.installedError')}</div> <div className='flex items-center px-2 pt-1 h-7 system-sm-semibold-uppercase'>{t('plugin.task.installedError')}</div>
<div className='flex items-center p-1 pl-2 h-8 rounded-lg hover:bg-state-base-hover'> {
<div className='relative flex items-center justify-center mr-2 w-6 h-6 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'> errorPlugins.map(errorPlugin => (
<RiErrorWarningFill className='absolute -right-0.5 -bottom-0.5 w-3 h-3 text-text-destructive' /> <div
</div> key={errorPlugin.plugin_unique_identifier}
<div className='grow system-md-regular text-text-secondary truncate'> className='flex items-center p-1 pl-2 h-8 rounded-lg hover:bg-state-base-hover'
DuckDuckGo Search >
</div> <div className='relative flex items-center justify-center mr-2 w-6 h-6 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'>
<Button <RiErrorWarningFill className='absolute -right-0.5 -bottom-0.5 w-3 h-3 text-text-destructive' />
size='small' <CardIcon
variant='ghost-accent' src={errorPlugin.icon}
> />
{t('common.operation.clear')} </div>
</Button> <div className='grow system-md-regular text-text-secondary truncate'>
</div> {errorPlugin.labels[language]}
</div>
<Button
size='small'
variant='ghost-accent'
onClick={() => handleClearErrorPlugin(errorPlugin.taskId, errorPlugin.plugin_id)}
>
{t('common.operation.clear')}
</Button>
</div>
))
}
</div> </div>
</PortalToFollowElemContent> </PortalToFollowElemContent>
</PortalToFollowElem> </PortalToFollowElem>

@ -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<PluginTasksStore>(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()
},
}))

@ -260,6 +260,9 @@ export type PluginStatus = {
plugin_id: string plugin_id: string
status: TaskStatus status: TaskStatus
message: string message: string
icon: string
labels: Record<Locale, string>
taskId: string
} }
export type PluginTask = { export type PluginTask = {

@ -12,7 +12,7 @@ import { pluginManifestToCardPluginProps } from '@/app/components/plugins/instal
import useGetIcon from '../install-plugin/base/use-get-icon' import useGetIcon from '../install-plugin/base/use-get-icon'
import { updateFromMarketPlace } from '@/service/plugins' import { updateFromMarketPlace } from '@/service/plugins'
import checkTaskStatus from '@/app/components/plugins/install-plugin/base/check-task-status' 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' const i18nPrefix = 'plugin.upgrade'
@ -56,7 +56,7 @@ const UpdatePluginModal: FC<Props> = ({
} }
const [uploadStep, setUploadStep] = useState<UploadStep>(UploadStep.notStarted) const [uploadStep, setUploadStep] = useState<UploadStep>(UploadStep.notStarted)
const setPluginTasksWithPolling = usePluginTasksStore(s => s.setPluginTasksWithPolling) const { handleRefetch } = usePluginTaskList()
const configBtnText = useMemo(() => { const configBtnText = useMemo(() => {
return ({ return ({
@ -82,7 +82,7 @@ const UpdatePluginModal: FC<Props> = ({
onSave() onSave()
return return
} }
setPluginTasksWithPolling() handleRefetch()
await check({ await check({
taskId, taskId,
pluginUniqueIdentifier: targetPackageInfo.id, pluginUniqueIdentifier: targetPackageInfo.id,
@ -98,7 +98,7 @@ const UpdatePluginModal: FC<Props> = ({
onSave() onSave()
onCancel() onCancel()
} }
}, [onCancel, onSave, uploadStep, check, originalPackageInfo.id, setPluginTasksWithPolling, targetPackageInfo.id]) }, [onCancel, onSave, uploadStep, check, originalPackageInfo.id, handleRefetch, targetPackageInfo.id])
const usedInAppInfo = useMemo(() => { const usedInAppInfo = useMemo(() => {
return ( return (
<div className='flex px-0.5 justify-center items-center gap-0.5'> <div className='flex px-0.5 justify-center items-center gap-0.5'>

@ -1,8 +1,10 @@
import { useCallback, useState } from 'react'
import type { import type {
DebugInfo as DebugInfoTypes, DebugInfo as DebugInfoTypes,
InstallPackageResponse, InstallPackageResponse,
InstalledPluginListResponse, InstalledPluginListResponse,
Permissions, Permissions,
PluginTask,
PluginsFromMarketplaceResponse, PluginsFromMarketplaceResponse,
} from '@/app/components/plugins/types' } from '@/app/components/plugins/types'
import type { 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}`)
},
})
}

Loading…
Cancel
Save