mirror of
https://github.com/langgenius/dify.git
synced 2025-12-19 17:27:16 -05:00
refactor: simplify plugin task handling and improve UI feedback (#26293)
This commit is contained in:
@@ -1,13 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react'
|
} 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 {
|
import {
|
||||||
useMutationClearAllTaskPlugin,
|
|
||||||
useMutationClearTaskPlugin,
|
useMutationClearTaskPlugin,
|
||||||
usePluginTaskList,
|
usePluginTaskList,
|
||||||
} from '@/service/use-plugins'
|
} from '@/service/use-plugins'
|
||||||
@@ -18,7 +14,6 @@ export const usePluginTaskStatus = () => {
|
|||||||
handleRefetch,
|
handleRefetch,
|
||||||
} = usePluginTaskList()
|
} = usePluginTaskList()
|
||||||
const { mutateAsync } = useMutationClearTaskPlugin()
|
const { mutateAsync } = useMutationClearTaskPlugin()
|
||||||
const { mutateAsync: mutateAsyncClearAll } = useMutationClearAllTaskPlugin()
|
|
||||||
const allPlugins = pluginTasks.map(task => task.plugins.map((plugin) => {
|
const allPlugins = pluginTasks.map(task => task.plugins.map((plugin) => {
|
||||||
return {
|
return {
|
||||||
...plugin,
|
...plugin,
|
||||||
@@ -45,10 +40,6 @@ export const usePluginTaskStatus = () => {
|
|||||||
})
|
})
|
||||||
handleRefetch()
|
handleRefetch()
|
||||||
}, [mutateAsync, handleRefetch])
|
}, [mutateAsync, handleRefetch])
|
||||||
const handleClearAllErrorPlugin = useCallback(async () => {
|
|
||||||
await mutateAsyncClearAll()
|
|
||||||
handleRefetch()
|
|
||||||
}, [mutateAsyncClearAll, handleRefetch])
|
|
||||||
const totalPluginsLength = allPlugins.length
|
const totalPluginsLength = allPlugins.length
|
||||||
const runningPluginsLength = runningPlugins.length
|
const runningPluginsLength = runningPlugins.length
|
||||||
const errorPluginsLength = errorPlugins.length
|
const errorPluginsLength = errorPlugins.length
|
||||||
@@ -60,26 +51,6 @@ export const usePluginTaskStatus = () => {
|
|||||||
const isSuccess = successPluginsLength === totalPluginsLength && totalPluginsLength > 0
|
const isSuccess = successPluginsLength === totalPluginsLength && totalPluginsLength > 0
|
||||||
const isFailed = runningPluginsLength === 0 && (errorPluginsLength + successPluginsLength) === totalPluginsLength && totalPluginsLength > 0 && errorPluginsLength > 0
|
const isFailed = runningPluginsLength === 0 && (errorPluginsLength + successPluginsLength) === totalPluginsLength && totalPluginsLength > 0 && errorPluginsLength > 0
|
||||||
|
|
||||||
const [opacity, setOpacity] = useState(1)
|
|
||||||
const timerRef = useRef<NodeJS.Timeout | null>(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isSuccess) {
|
|
||||||
if (timerRef.current) {
|
|
||||||
clearTimeout(timerRef.current)
|
|
||||||
timerRef.current = null
|
|
||||||
}
|
|
||||||
if (opacity > 0) {
|
|
||||||
timerRef.current = setTimeout(() => {
|
|
||||||
setOpacity(v => v - 0.1)
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSuccess)
|
|
||||||
setOpacity(1)
|
|
||||||
}, [isSuccess, opacity])
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
errorPlugins,
|
errorPlugins,
|
||||||
successPlugins,
|
successPlugins,
|
||||||
@@ -94,7 +65,5 @@ export const usePluginTaskStatus = () => {
|
|||||||
isSuccess,
|
isSuccess,
|
||||||
isFailed,
|
isFailed,
|
||||||
handleClearErrorPlugin,
|
handleClearErrorPlugin,
|
||||||
handleClearAllErrorPlugin,
|
|
||||||
opacity,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
useCallback,
|
||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
@@ -6,6 +7,7 @@ import {
|
|||||||
RiCheckboxCircleFill,
|
RiCheckboxCircleFill,
|
||||||
RiErrorWarningFill,
|
RiErrorWarningFill,
|
||||||
RiInstallLine,
|
RiInstallLine,
|
||||||
|
RiLoaderLine,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { usePluginTaskStatus } from './hooks'
|
import { usePluginTaskStatus } from './hooks'
|
||||||
@@ -14,7 +16,6 @@ import {
|
|||||||
PortalToFollowElemContent,
|
PortalToFollowElemContent,
|
||||||
PortalToFollowElemTrigger,
|
PortalToFollowElemTrigger,
|
||||||
} from '@/app/components/base/portal-to-follow-elem'
|
} from '@/app/components/base/portal-to-follow-elem'
|
||||||
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 CardIcon from '@/app/components/plugins/card/base/card-icon'
|
||||||
@@ -22,6 +23,7 @@ import cn from '@/utils/classnames'
|
|||||||
import { useGetLanguage } from '@/context/i18n'
|
import { useGetLanguage } from '@/context/i18n'
|
||||||
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
|
||||||
import DownloadingIcon from '@/app/components/header/plugins-nav/downloading-icon'
|
import DownloadingIcon from '@/app/components/header/plugins-nav/downloading-icon'
|
||||||
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
|
|
||||||
const PluginTasks = () => {
|
const PluginTasks = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -29,6 +31,8 @@ const PluginTasks = () => {
|
|||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const {
|
const {
|
||||||
errorPlugins,
|
errorPlugins,
|
||||||
|
successPlugins,
|
||||||
|
runningPlugins,
|
||||||
runningPluginsLength,
|
runningPluginsLength,
|
||||||
successPluginsLength,
|
successPluginsLength,
|
||||||
errorPluginsLength,
|
errorPluginsLength,
|
||||||
@@ -39,33 +43,69 @@ const PluginTasks = () => {
|
|||||||
isSuccess,
|
isSuccess,
|
||||||
isFailed,
|
isFailed,
|
||||||
handleClearErrorPlugin,
|
handleClearErrorPlugin,
|
||||||
handleClearAllErrorPlugin,
|
|
||||||
opacity,
|
|
||||||
} = usePluginTaskStatus()
|
} = usePluginTaskStatus()
|
||||||
const { getIconUrl } = useGetIcon()
|
const { getIconUrl } = useGetIcon()
|
||||||
|
|
||||||
|
const handleClearAllWithModal = useCallback(async () => {
|
||||||
|
// Clear all completed plugins (success and error) but keep running ones
|
||||||
|
const completedPlugins = [...successPlugins, ...errorPlugins]
|
||||||
|
|
||||||
|
// Clear all completed plugins individually
|
||||||
|
for (const plugin of completedPlugins)
|
||||||
|
await handleClearErrorPlugin(plugin.taskId, plugin.plugin_unique_identifier)
|
||||||
|
|
||||||
|
// Only close modal if no plugins are still installing
|
||||||
|
if (runningPluginsLength === 0)
|
||||||
|
setOpen(false)
|
||||||
|
}, [successPlugins, errorPlugins, handleClearErrorPlugin, runningPluginsLength])
|
||||||
|
|
||||||
|
const handleClearErrorsWithModal = useCallback(async () => {
|
||||||
|
// Clear only error plugins, not all plugins
|
||||||
|
for (const plugin of errorPlugins)
|
||||||
|
await handleClearErrorPlugin(plugin.taskId, plugin.plugin_unique_identifier)
|
||||||
|
// Only close modal if no plugins are still installing
|
||||||
|
if (runningPluginsLength === 0)
|
||||||
|
setOpen(false)
|
||||||
|
}, [errorPlugins, handleClearErrorPlugin, runningPluginsLength])
|
||||||
|
|
||||||
|
const handleClearSingleWithModal = useCallback(async (taskId: string, pluginId: string) => {
|
||||||
|
await handleClearErrorPlugin(taskId, pluginId)
|
||||||
|
// Only close modal if no plugins are still installing
|
||||||
|
if (runningPluginsLength === 0)
|
||||||
|
setOpen(false)
|
||||||
|
}, [handleClearErrorPlugin, runningPluginsLength])
|
||||||
|
|
||||||
const tip = useMemo(() => {
|
const tip = useMemo(() => {
|
||||||
if (isInstalling)
|
|
||||||
return t('plugin.task.installing', { installingLength: runningPluginsLength })
|
|
||||||
|
|
||||||
if (isInstallingWithSuccess)
|
|
||||||
return t('plugin.task.installingWithSuccess', { installingLength: runningPluginsLength, successLength: successPluginsLength })
|
|
||||||
|
|
||||||
if (isInstallingWithError)
|
if (isInstallingWithError)
|
||||||
return t('plugin.task.installingWithError', { installingLength: runningPluginsLength, successLength: successPluginsLength, errorLength: errorPluginsLength })
|
return t('plugin.task.installingWithError', { installingLength: runningPluginsLength, successLength: successPluginsLength, errorLength: errorPluginsLength })
|
||||||
|
if (isInstallingWithSuccess)
|
||||||
|
return t('plugin.task.installingWithSuccess', { installingLength: runningPluginsLength, successLength: successPluginsLength })
|
||||||
|
if (isInstalling)
|
||||||
|
return t('plugin.task.installing')
|
||||||
if (isFailed)
|
if (isFailed)
|
||||||
return t('plugin.task.installError', { errorLength: errorPluginsLength })
|
return t('plugin.task.installedError', { errorLength: errorPluginsLength })
|
||||||
}, [isInstalling, isInstallingWithSuccess, isInstallingWithError, isFailed, errorPluginsLength, runningPluginsLength, successPluginsLength, t])
|
if (isSuccess)
|
||||||
|
return t('plugin.task.installSuccess', { successLength: successPluginsLength })
|
||||||
|
return t('plugin.task.installed')
|
||||||
|
}, [
|
||||||
|
errorPluginsLength,
|
||||||
|
isFailed,
|
||||||
|
isInstalling,
|
||||||
|
isInstallingWithError,
|
||||||
|
isInstallingWithSuccess,
|
||||||
|
isSuccess,
|
||||||
|
runningPluginsLength,
|
||||||
|
successPluginsLength,
|
||||||
|
t,
|
||||||
|
])
|
||||||
|
|
||||||
if (!totalPluginsLength)
|
// Show icon if there are any plugin tasks (completed, running, or failed)
|
||||||
|
// Only hide when there are absolutely no plugin tasks
|
||||||
|
if (totalPluginsLength === 0)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className='flex items-center'>
|
||||||
className={cn('flex items-center', opacity < 0 && 'hidden')}
|
|
||||||
style={{ opacity }}
|
|
||||||
>
|
|
||||||
<PortalToFollowElem
|
<PortalToFollowElem
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setOpen}
|
||||||
@@ -77,15 +117,20 @@ const PluginTasks = () => {
|
|||||||
>
|
>
|
||||||
<PortalToFollowElemTrigger
|
<PortalToFollowElemTrigger
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isFailed)
|
if (isFailed || isInstalling || isInstallingWithSuccess || isInstallingWithError || isSuccess)
|
||||||
setOpen(v => !v)
|
setOpen(v => !v)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tooltip popupContent={tip}>
|
<Tooltip
|
||||||
|
popupContent={tip}
|
||||||
|
asChild
|
||||||
|
offset={8}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex h-8 w-8 items-center justify-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg shadow-xs hover:bg-components-button-secondary-bg-hover',
|
'relative flex h-8 w-8 items-center justify-center rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg shadow-xs hover:bg-components-button-secondary-bg-hover',
|
||||||
(isInstallingWithError || isFailed) && 'cursor-pointer border-components-button-destructive-secondary-border-hover bg-state-destructive-hover hover:bg-state-destructive-hover-alt',
|
(isInstallingWithError || isFailed) && 'cursor-pointer border-components-button-destructive-secondary-border-hover bg-state-destructive-hover hover:bg-state-destructive-hover-alt',
|
||||||
|
(isInstalling || isInstallingWithSuccess || isSuccess) && 'cursor-pointer hover:bg-components-button-secondary-bg-hover',
|
||||||
)}
|
)}
|
||||||
id="plugin-task-trigger"
|
id="plugin-task-trigger"
|
||||||
>
|
>
|
||||||
@@ -124,7 +169,7 @@ const PluginTasks = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
isSuccess && (
|
(isSuccess || (successPluginsLength > 0 && runningPluginsLength === 0 && errorPluginsLength === 0)) && (
|
||||||
<RiCheckboxCircleFill className='h-3.5 w-3.5 text-text-success' />
|
<RiCheckboxCircleFill className='h-3.5 w-3.5 text-text-success' />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -138,52 +183,129 @@ const PluginTasks = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
<PortalToFollowElemContent className='z-[11]'>
|
<PortalToFollowElemContent className='z-[11]'>
|
||||||
<div className='w-[320px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 pb-2 shadow-lg'>
|
<div className='w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg'>
|
||||||
<div className='system-sm-semibold-uppercase sticky top-0 flex h-7 items-center justify-between px-2 pt-1'>
|
{/* Running Plugins */}
|
||||||
{t('plugin.task.installedError', { errorLength: errorPluginsLength })}
|
{runningPlugins.length > 0 && (
|
||||||
<Button
|
<>
|
||||||
className='shrink-0'
|
<div className='system-sm-semibold-uppercase sticky top-0 flex h-7 items-center justify-between px-2 pt-1'>
|
||||||
size='small'
|
{t('plugin.task.installing')} ({runningPlugins.length})
|
||||||
variant='ghost'
|
</div>
|
||||||
onClick={() => handleClearAllErrorPlugin()}
|
<div className='max-h-[200px] overflow-y-auto'>
|
||||||
>
|
{runningPlugins.map(runningPlugin => (
|
||||||
{t('plugin.task.clearAll')}
|
<div
|
||||||
</Button>
|
key={runningPlugin.plugin_unique_identifier}
|
||||||
</div>
|
className='flex items-center rounded-lg p-2 hover:bg-state-base-hover'
|
||||||
<div className='max-h-[400px] overflow-y-auto'>
|
|
||||||
{
|
|
||||||
errorPlugins.map(errorPlugin => (
|
|
||||||
<div
|
|
||||||
key={errorPlugin.plugin_unique_identifier}
|
|
||||||
className='flex rounded-lg p-2 hover:bg-state-base-hover'
|
|
||||||
>
|
|
||||||
<div className='relative mr-2 flex h-6 w-6 items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'>
|
|
||||||
<RiErrorWarningFill className='absolute -bottom-0.5 -right-0.5 z-10 h-3 w-3 text-text-destructive' />
|
|
||||||
<CardIcon
|
|
||||||
size='tiny'
|
|
||||||
src={getIconUrl(errorPlugin.icon)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='grow'>
|
|
||||||
<div className='system-md-regular truncate text-text-secondary'>
|
|
||||||
{errorPlugin.labels[language]}
|
|
||||||
</div>
|
|
||||||
<div className='system-xs-regular break-all text-text-destructive'>
|
|
||||||
{errorPlugin.message}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
className='shrink-0'
|
|
||||||
size='small'
|
|
||||||
variant='ghost'
|
|
||||||
onClick={() => handleClearErrorPlugin(errorPlugin.taskId, errorPlugin.plugin_unique_identifier)}
|
|
||||||
>
|
>
|
||||||
{t('common.operation.clear')}
|
<div className='relative mr-2 flex h-6 w-6 items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'>
|
||||||
</Button>
|
<RiLoaderLine className='absolute -bottom-0.5 -right-0.5 z-10 h-3 w-3 animate-spin text-text-accent' />
|
||||||
</div>
|
<CardIcon
|
||||||
))
|
size='tiny'
|
||||||
}
|
src={getIconUrl(runningPlugin.icon)}
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='grow'>
|
||||||
|
<div className='system-md-regular truncate text-text-secondary'>
|
||||||
|
{runningPlugin.labels[language]}
|
||||||
|
</div>
|
||||||
|
<div className='system-xs-regular text-text-tertiary'>
|
||||||
|
{t('plugin.task.installing')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Success Plugins */}
|
||||||
|
{successPlugins.length > 0 && (
|
||||||
|
<>
|
||||||
|
<div className='system-sm-semibold-uppercase sticky top-0 flex h-7 items-center justify-between px-2 pt-1'>
|
||||||
|
{t('plugin.task.installed')} ({successPlugins.length})
|
||||||
|
<Button
|
||||||
|
className='shrink-0'
|
||||||
|
size='small'
|
||||||
|
variant='ghost'
|
||||||
|
onClick={() => handleClearAllWithModal()}
|
||||||
|
>
|
||||||
|
{t('plugin.task.clearAll')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className='max-h-[200px] overflow-y-auto'>
|
||||||
|
{successPlugins.map(successPlugin => (
|
||||||
|
<div
|
||||||
|
key={successPlugin.plugin_unique_identifier}
|
||||||
|
className='flex items-center rounded-lg p-2 hover:bg-state-base-hover'
|
||||||
|
>
|
||||||
|
<div className='relative mr-2 flex h-6 w-6 items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'>
|
||||||
|
<RiCheckboxCircleFill className='absolute -bottom-0.5 -right-0.5 z-10 h-3 w-3 text-text-success' />
|
||||||
|
<CardIcon
|
||||||
|
size='tiny'
|
||||||
|
src={getIconUrl(successPlugin.icon)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='grow'>
|
||||||
|
<div className='system-md-regular truncate text-text-secondary'>
|
||||||
|
{successPlugin.labels[language]}
|
||||||
|
</div>
|
||||||
|
<div className='system-xs-regular text-text-success'>
|
||||||
|
{successPlugin.message || t('plugin.task.installed')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Error Plugins */}
|
||||||
|
{errorPlugins.length > 0 && (
|
||||||
|
<>
|
||||||
|
<div className='system-sm-semibold-uppercase sticky top-0 flex h-7 items-center justify-between px-2 pt-1'>
|
||||||
|
{t('plugin.task.installError', { errorLength: errorPlugins.length })}
|
||||||
|
<Button
|
||||||
|
className='shrink-0'
|
||||||
|
size='small'
|
||||||
|
variant='ghost'
|
||||||
|
onClick={() => handleClearErrorsWithModal()}
|
||||||
|
>
|
||||||
|
{t('plugin.task.clearAll')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className='max-h-[200px] overflow-y-auto'>
|
||||||
|
{errorPlugins.map(errorPlugin => (
|
||||||
|
<div
|
||||||
|
key={errorPlugin.plugin_unique_identifier}
|
||||||
|
className='flex items-center rounded-lg p-2 hover:bg-state-base-hover'
|
||||||
|
>
|
||||||
|
<div className='relative mr-2 flex h-6 w-6 items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge'>
|
||||||
|
<RiErrorWarningFill className='absolute -bottom-0.5 -right-0.5 z-10 h-3 w-3 text-text-destructive' />
|
||||||
|
<CardIcon
|
||||||
|
size='tiny'
|
||||||
|
src={getIconUrl(errorPlugin.icon)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='grow'>
|
||||||
|
<div className='system-md-regular truncate text-text-secondary'>
|
||||||
|
{errorPlugin.labels[language]}
|
||||||
|
</div>
|
||||||
|
<div className='system-xs-regular break-all text-text-destructive'>
|
||||||
|
{errorPlugin.message}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
className='shrink-0'
|
||||||
|
size='small'
|
||||||
|
variant='ghost'
|
||||||
|
onClick={() => handleClearSingleWithModal(errorPlugin.taskId, errorPlugin.plugin_unique_identifier)}
|
||||||
|
>
|
||||||
|
{t('common.operation.clear')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</PortalToFollowElemContent>
|
</PortalToFollowElemContent>
|
||||||
</PortalToFollowElem>
|
</PortalToFollowElem>
|
||||||
|
|||||||
@@ -270,12 +270,17 @@ const translation = {
|
|||||||
partnerTip: 'Verified by a Dify partner',
|
partnerTip: 'Verified by a Dify partner',
|
||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
installing: 'Installing {{installingLength}} plugins, 0 done.',
|
installing: 'Installing plugins',
|
||||||
installingWithSuccess: 'Installing {{installingLength}} plugins, {{successLength}} success.',
|
installingWithSuccess: 'Installing {{installingLength}} plugins, {{successLength}} success.',
|
||||||
installingWithError: 'Installing {{installingLength}} plugins, {{successLength}} success, {{errorLength}} failed',
|
installingWithError: 'Installing {{installingLength}} plugins, {{successLength}} success, {{errorLength}} failed',
|
||||||
installError: '{{errorLength}} plugins failed to install, click to view',
|
installError: '{{errorLength}} plugins failed to install, click to view',
|
||||||
installedError: '{{errorLength}} plugins failed to install',
|
installedError: '{{errorLength}} plugins failed to install',
|
||||||
|
installSuccess: '{{successLength}} plugins installed successfully',
|
||||||
|
installed: 'Installed',
|
||||||
clearAll: 'Clear all',
|
clearAll: 'Clear all',
|
||||||
|
runningPlugins: 'Installing Plugins',
|
||||||
|
successPlugins: 'Successfully Installed Plugins',
|
||||||
|
errorPlugins: 'Failed to Install Plugins',
|
||||||
},
|
},
|
||||||
requestAPlugin: 'Request a plugin',
|
requestAPlugin: 'Request a plugin',
|
||||||
publishPlugins: 'Publish plugins',
|
publishPlugins: 'Publish plugins',
|
||||||
|
|||||||
@@ -270,12 +270,17 @@ const translation = {
|
|||||||
partnerTip: '此插件由 Dify 合作伙伴认证',
|
partnerTip: '此插件由 Dify 合作伙伴认证',
|
||||||
},
|
},
|
||||||
task: {
|
task: {
|
||||||
installing: '{{installingLength}} 个插件安装中,0 已完成',
|
installing: '正在安装插件',
|
||||||
installingWithSuccess: '{{installingLength}} 个插件安装中,{{successLength}} 安装成功',
|
installingWithSuccess: '{{installingLength}} 个插件安装中,{{successLength}} 安装成功',
|
||||||
installingWithError: '{{installingLength}} 个插件安装中,{{successLength}} 安装成功,{{errorLength}} 安装失败',
|
installingWithError: '{{installingLength}} 个插件安装中,{{successLength}} 安装成功,{{errorLength}} 安装失败',
|
||||||
installError: '{{errorLength}} 个插件安装失败,点击查看',
|
installError: '{{errorLength}} 个插件安装失败,点击查看',
|
||||||
installedError: '{{errorLength}} 个插件安装失败',
|
installedError: '{{errorLength}} 个插件安装失败',
|
||||||
|
installSuccess: '{{successLength}} 个插件安装成功',
|
||||||
|
installed: '已安装',
|
||||||
clearAll: '清除所有',
|
clearAll: '清除所有',
|
||||||
|
runningPlugins: '正在安装的插件',
|
||||||
|
successPlugins: '安装成功的插件',
|
||||||
|
errorPlugins: '安装失败的插件',
|
||||||
},
|
},
|
||||||
requestAPlugin: '申请插件',
|
requestAPlugin: '申请插件',
|
||||||
publishPlugins: '发布插件',
|
publishPlugins: '发布插件',
|
||||||
|
|||||||
@@ -634,7 +634,8 @@ export const usePluginTaskList = (category?: PluginCategoryEnum | string) => {
|
|||||||
export const useMutationClearTaskPlugin = () => {
|
export const useMutationClearTaskPlugin = () => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ taskId, pluginId }: { taskId: string; pluginId: string }) => {
|
mutationFn: ({ taskId, pluginId }: { taskId: string; pluginId: string }) => {
|
||||||
return post<{ success: boolean }>(`/workspaces/current/plugin/tasks/${taskId}/delete/${pluginId}`)
|
const encodedPluginId = encodeURIComponent(pluginId)
|
||||||
|
return post<{ success: boolean }>(`/workspaces/current/plugin/tasks/${taskId}/delete/${encodedPluginId}`)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user