diff --git a/web/app/components/plugins/marketplace/context.tsx b/web/app/components/plugins/marketplace/context.tsx index 31fe2ced5e..4b692cac28 100644 --- a/web/app/components/plugins/marketplace/context.tsx +++ b/web/app/components/plugins/marketplace/context.tsx @@ -29,6 +29,7 @@ import { useMarketplaceCollectionsAndPlugins, useMarketplacePlugins, } from './hooks' +import { getMarketplaceListCondition } from './utils' export type MarketplaceContextValue = { intersected: boolean @@ -134,6 +135,7 @@ export const MarketplaceContextProvider = ({ if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) { queryMarketplaceCollectionsAndPlugins({ category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current, + condition: getMarketplaceListCondition(activePluginTypeRef.current), }) resetPlugins() @@ -156,6 +158,7 @@ export const MarketplaceContextProvider = ({ if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) { queryMarketplaceCollectionsAndPlugins({ category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current, + condition: getMarketplaceListCondition(activePluginTypeRef.current), }) resetPlugins() @@ -178,6 +181,7 @@ export const MarketplaceContextProvider = ({ if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) { queryMarketplaceCollectionsAndPlugins({ category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type, + condition: getMarketplaceListCondition(type), }) resetPlugins() diff --git a/web/app/components/plugins/marketplace/types.ts b/web/app/components/plugins/marketplace/types.ts index fbe4595322..58424d6c68 100644 --- a/web/app/components/plugins/marketplace/types.ts +++ b/web/app/components/plugins/marketplace/types.ts @@ -36,6 +36,7 @@ export type PluginsSort = { export type CollectionsAndPluginsSearchParams = { category?: string + condition?: string } export type SearchParams = { diff --git a/web/app/components/plugins/marketplace/utils.ts b/web/app/components/plugins/marketplace/utils.ts index a8e50b5e20..c9f77318f7 100644 --- a/web/app/components/plugins/marketplace/utils.ts +++ b/web/app/components/plugins/marketplace/utils.ts @@ -1,4 +1,5 @@ import type { Plugin } from '@/app/components/plugins/types' +import { PluginType } from '@/app/components/plugins/types' import type { CollectionsAndPluginsSearchParams, MarketplaceCollection, @@ -14,7 +15,10 @@ export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAnd let marketplaceCollections = [] as MarketplaceCollection[] let marketplaceCollectionPluginsMap = {} as Record try { - const marketplaceCollectionsData = await globalThis.fetch(`${MARKETPLACE_API_PREFIX}/collections?page=1&page_size=100`, { cache: 'no-store' }) + let marketplaceUrl = `${MARKETPLACE_API_PREFIX}/collections?page=1&page_size=100` + if (query?.condition) + marketplaceUrl += `&condition=${query.condition}` + const marketplaceCollectionsData = await globalThis.fetch(marketplaceUrl, { cache: 'no-store' }) const marketplaceCollectionsDataJson = await marketplaceCollectionsData.json() marketplaceCollections = marketplaceCollectionsDataJson.data.collections await Promise.all(marketplaceCollections.map(async (collection: MarketplaceCollection) => { @@ -83,3 +87,16 @@ export const getMarketplacePlugins = async (query: PluginsSearchParams) => { marketplacePlugins, } } + +export const getMarketplaceListCondition = (pluginType: string) => { + if (pluginType === PluginType.tool) + return 'category=tool' + + if (pluginType === PluginType.model) + return 'category=model' + + if (pluginType === PluginType.extension) + return 'category=endpoint' + + return '' +} diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts b/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts index 3ebafe5ba6..a7abcb644b 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts +++ b/web/app/components/plugins/plugin-page/plugin-tasks/hooks.ts @@ -1,4 +1,9 @@ -import { useCallback } from 'react' +import { + useCallback, + useEffect, + useRef, + useState, +} from 'react' import { TaskStatus } from '@/app/components/plugins/types' import type { PluginStatus } from '@/app/components/plugins/types' import { @@ -36,12 +41,49 @@ export const usePluginTaskStatus = () => { pluginId, }) }, [mutate]) + const totalPluginsLength = allPlugins.length + const runningPluginsLength = runningPlugins.length + const errorPluginsLength = errorPlugins.length + const successPluginsLength = successPlugins.length + + const isInstalling = runningPluginsLength > 0 && errorPluginsLength === 0 && successPluginsLength === 0 + const isInstallingWithSuccess = runningPluginsLength > 0 && successPluginsLength > 0 && errorPluginsLength === 0 + const isInstallingWithError = runningPluginsLength > 0 && errorPluginsLength > 0 + const isSuccess = successPluginsLength === totalPluginsLength && totalPluginsLength > 0 + const isFailed = runningPluginsLength === 0 && (errorPluginsLength + successPluginsLength) === totalPluginsLength && totalPluginsLength > 0 && errorPluginsLength > 0 + + const [opacity, setOpacity] = useState(1) + const timerRef = useRef(null) + + useEffect(() => { + if (isSuccess && opacity > 0) { + if (timerRef.current) { + clearTimeout(timerRef.current) + timerRef.current = null + } + timerRef.current = setTimeout(() => { + setOpacity(v => v - 0.1) + }, 200) + } + + if (!isSuccess) + setOpacity(1) + }, [isSuccess, opacity]) return { errorPlugins, successPlugins, runningPlugins, - totalPluginsLength: allPlugins.length, + runningPluginsLength, + errorPluginsLength, + successPluginsLength, + totalPluginsLength, + isInstalling, + isInstallingWithSuccess, + isInstallingWithError, + isSuccess, + isFailed, handleClearErrorPlugin, + opacity, } } 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 7071da0af4..b3165e7046 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx +++ b/web/app/components/plugins/plugin-page/plugin-tasks/index.tsx @@ -28,37 +28,42 @@ const PluginTasks = () => { const [open, setOpen] = useState(false) const { errorPlugins, - runningPlugins, - successPlugins, + runningPluginsLength, + successPluginsLength, + errorPluginsLength, totalPluginsLength, + isInstalling, + isInstallingWithSuccess, + isInstallingWithError, + isSuccess, + isFailed, handleClearErrorPlugin, + opacity, } = usePluginTaskStatus() const { getIconUrl } = useGetIcon() - const runningPluginsLength = runningPlugins.length - const errorPluginsLength = errorPlugins.length - const successPluginsLength = successPlugins.length - - const isInstalling = runningPluginsLength > 0 && errorPluginsLength === 0 - const isInstallingWithError = runningPluginsLength > 0 && errorPluginsLength > 0 - const isSuccess = successPluginsLength === totalPluginsLength && totalPluginsLength > 0 - const isFailed = runningPluginsLength === 0 && (errorPluginsLength + successPluginsLength) === totalPluginsLength && totalPluginsLength > 0 const tip = useMemo(() => { if (isInstalling) - return t('plugin.task.installing', { installingLength: runningPlugins.length, totalLength: totalPluginsLength }) + return t('plugin.task.installing', { installingLength: runningPluginsLength }) + + if (isInstallingWithSuccess) + return t('plugin.task.installingWithSuccess', { installingLength: runningPluginsLength, successLength: successPluginsLength }) if (isInstallingWithError) - return t('plugin.task.installingWithError', { installingLength: runningPlugins.length, totalLength: totalPluginsLength, errorLength: errorPlugins.length }) + return t('plugin.task.installingWithError', { installingLength: runningPluginsLength, successLength: successPluginsLength, errorLength: errorPluginsLength }) if (isFailed) - return t('plugin.task.installError', { errorLength: errorPlugins.length }) - }, [isInstalling, isInstallingWithError, isFailed, errorPlugins, runningPlugins, totalPluginsLength, t]) + return t('plugin.task.installError', { errorLength: errorPluginsLength }) + }, [isInstalling, isInstallingWithSuccess, isInstallingWithError, isFailed, errorPluginsLength, runningPluginsLength, successPluginsLength, t]) if (!totalPluginsLength) return null return ( -
+
{ > { - if (isFailed || isInstallingWithError) + if (isFailed) setOpen(v => !v) }} > @@ -89,16 +94,17 @@ const PluginTasks = () => { />
{ - isInstalling && ( + (isInstalling || isInstallingWithSuccess) && ( ) } { isInstallingWithError && ( {
-
- {t('plugin.task.installedError', { errorLength: errorPlugins.length })} +
+ {t('plugin.task.installedError', { errorLength: errorPluginsLength })} +
- { - errorPlugins.map(errorPlugin => ( -
-
- - -
-
- {errorPlugin.labels[language]} -
- -
- )) - } +
+ + +
+
+
+ {errorPlugin.labels[language]} +
+
+ {errorPlugin.message} +
+
+ +
+ )) + } +
diff --git a/web/app/components/plugins/utils.ts b/web/app/components/plugins/utils.ts index a87ee021eb..95f6d716d9 100644 --- a/web/app/components/plugins/utils.ts +++ b/web/app/components/plugins/utils.ts @@ -8,6 +8,5 @@ export const getValidTagKeys = (tags: string[]) => { } export const getValidCategoryKeys = (category?: string) => { - const currentCategory = categoryKeys.find(key => key === category) - return currentCategory ? `${currentCategory}s` : '' + return categoryKeys.find(key => key === category) } diff --git a/web/app/components/tools/marketplace/hooks.ts b/web/app/components/tools/marketplace/hooks.ts index 45cbd8a389..3aec42be75 100644 --- a/web/app/components/tools/marketplace/hooks.ts +++ b/web/app/components/tools/marketplace/hooks.ts @@ -6,6 +6,7 @@ import { useMarketplacePlugins, } from '@/app/components/plugins/marketplace/hooks' import { PluginType } from '@/app/components/plugins/types' +import { getMarketplaceListCondition } from '@/app/components/plugins/marketplace/utils' export const useMarketplace = (searchPluginText: string, filterPluginTags: string[]) => { const { @@ -39,7 +40,10 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin }) } else { - queryMarketplaceCollectionsAndPlugins({ category: PluginType.tool }) + queryMarketplaceCollectionsAndPlugins({ + category: PluginType.tool, + condition: getMarketplaceListCondition(PluginType.tool), + }) resetPlugins() } }, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, resetPlugins]) diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts index 88c21c0dd3..69b2df6a53 100644 --- a/web/i18n/en-US/plugin.ts +++ b/web/i18n/en-US/plugin.ts @@ -162,10 +162,12 @@ const translation = { }, }, task: { - installing: 'Installing {{installingLength}}/{{totalLength}} plugins...', - installingWithError: 'Installing {{installingLength}} of {{totalLength}} plugins, {{errorLength}} failed, click to view', + installing: 'Installing {{installingLength}} plugins, 0 done.', + installingWithSuccess: 'Installing {{installingLength}} plugins, {{successLength}} success.', + installingWithError: 'Installing {{installingLength}} plugins, {{successLength}} success, {{errorLength}} failed', installError: '{{errorLength}} plugins failed to install, click to view', installedError: '{{errorLength}} plugins failed to install', + clearAll: 'Clear all', }, } diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts index 94e1324bed..a54d11e351 100644 --- a/web/i18n/zh-Hans/plugin.ts +++ b/web/i18n/zh-Hans/plugin.ts @@ -162,10 +162,12 @@ const translation = { }, }, task: { - installing: '{{installingLength}}/{{totalLength}} 插件安装中...', - installingWithError: '{{installingLength}}/{{totalLength}} 插件安装中,{{errorLength}} 安装失败。点击查看', + installing: '{{installingLength}} 个插件安装中,0 已完成', + installingWithSuccess: '{{installingLength}} 个插件安装中,{{successLength}} 安装成功', + installingWithError: '{{installingLength}} 个插件安装中,{{successLength}} 安装成功,{{errorLength}} 安装失败', installError: '{{errorLength}} 个插件安装失败,点击查看', installedError: '{{errorLength}} 个插件安装失败', + clearAll: '清除所有', }, }