From df049564e8a42bbd8472f8a5a6a628063db29e6b Mon Sep 17 00:00:00 2001 From: Joel Date: Mon, 25 Nov 2024 18:01:03 +0800 Subject: [PATCH] feat: support install bundle from marketplace --- .../install-bundle/steps/install-multi.tsx | 26 +++++++---- .../install-from-marketplace/index.tsx | 46 ++++++++++--------- .../steps/install.tsx | 2 +- .../components/plugins/plugin-page/index.tsx | 27 ++++++++++- web/service/plugins.ts | 9 ++++ web/service/use-plugins.ts | 1 + 6 files changed, 79 insertions(+), 32 deletions(-) diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx index 07119357aa..445c8be9d9 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx @@ -22,8 +22,10 @@ const InstallByDSLList: FC = ({ onSelect, onLoadedAllPlugin, }) => { - const { isLoading: isFetchingMarketplaceDataFromDSL, data: marketplaceFromDSLRes } = useFetchPluginsInMarketPlaceByIds(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value.plugin_unique_identifier!)) - const { isLoading: isFetchingMarketplaceDataFromLocal, data: marketplaceResFromLocalRes } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value!)) + // DSL has id, to get plugin info to show more info + const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByIds(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value.plugin_unique_identifier!)) + // has meta(org,name,version), to get id + const { isLoading: isFetchingDataByMeta, data: infoByMeta, error: infoByMetaError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value!)) const [plugins, doSetPlugins] = useState<(Plugin | undefined)[]>((() => { const hasLocalPackage = allPlugins.some(d => d.type === 'package') if (!hasLocalPackage) @@ -75,8 +77,8 @@ const InstallByDSLList: FC = ({ }, [allPlugins]) useEffect(() => { - if (!isFetchingMarketplaceDataFromDSL && marketplaceFromDSLRes?.data.plugins) { - const payloads = marketplaceFromDSLRes?.data.plugins + if (!isFetchingMarketplaceDataById && infoGetById?.data.plugins) { + const payloads = infoGetById?.data.plugins const failedIndex: number[] = [] const nextPlugins = produce(pluginsRef.current, (draft) => { marketPlaceInDSLIndex.forEach((index, i) => { @@ -92,11 +94,11 @@ const InstallByDSLList: FC = ({ setErrorIndexes([...errorIndexes, ...failedIndex]) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isFetchingMarketplaceDataFromDSL]) + }, [isFetchingMarketplaceDataById]) useEffect(() => { - if (!isFetchingMarketplaceDataFromLocal && marketplaceResFromLocalRes?.data.list) { - const payloads = marketplaceResFromLocalRes?.data.list + if (!isFetchingDataByMeta && infoByMeta?.data.list) { + const payloads = infoByMeta?.data.list const failedIndex: number[] = [] const nextPlugins = produce(pluginsRef.current, (draft) => { marketPlaceInDSLIndex.forEach((index, i) => { @@ -117,7 +119,15 @@ const InstallByDSLList: FC = ({ setErrorIndexes([...errorIndexes, ...failedIndex]) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isFetchingMarketplaceDataFromLocal]) + }, [isFetchingDataByMeta]) + + useEffect(() => { + // get info all failed + if (infoByMetaError || infoByIdError) + setErrorIndexes([...errorIndexes, ...marketPlaceInDSLIndex]) + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [infoByMetaError, infoByIdError]) const isLoadedAllData = (plugins.filter(p => !!p).length + errorIndexes.length) === allPlugins.length useEffect(() => { diff --git a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx index 44b63cf7dd..5a3621995a 100644 --- a/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-marketplace/index.tsx @@ -55,7 +55,7 @@ const InstallFromMarketplace: React.FC = ({ updateModelProviders() if (PluginType.tool.includes(manifest.category)) invalidateAllToolProviders() - }, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest.category, updateModelProviders]) + }, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest, updateModelProviders]) const handleFailed = useCallback((errorMsg?: string) => { setStep(InstallStep.installFailed) @@ -76,17 +76,6 @@ const InstallFromMarketplace: React.FC = ({ {getTitle()} - { - step === InstallStep.readyToInstall && ( - - ) - } { isBundle ? ( = ({ onClose={onClose} allPlugins={dependencies!} /> - ) : ([InstallStep.installed, InstallStep.installFailed].includes(step)) && ( - + ) : (<> + { + step === InstallStep.readyToInstall && ( + + )} + { + [InstallStep.installed, InstallStep.installFailed].includes(step) && ( + + ) + } + ) } - + ) } diff --git a/web/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx b/web/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx index 596dc1c05e..cc7303a4c4 100644 --- a/web/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx +++ b/web/app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx @@ -94,7 +94,7 @@ const Installed: FC = ({ ) }) - }, [payload.latest_version, supportCheckInstalled]) + }, [payload.latest_version, payload.version, supportCheckInstalled]) return ( <> diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx index 26cf4b1659..f5b354effc 100644 --- a/web/app/components/plugins/plugin-page/index.tsx +++ b/web/app/components/plugins/plugin-page/index.tsx @@ -28,13 +28,15 @@ import { useRouter, useSearchParams, } from 'next/navigation' +import type { Dependency } from '../types' import type { PluginDeclaration, PluginManifestInMarket } from '../types' import { sleep } from '@/utils' -import { fetchManifestFromMarketPlace } from '@/service/plugins' +import { fetchBundleInfoFromMarketPlace, fetchManifestFromMarketPlace } from '@/service/plugins' import { marketplaceApiPrefix } from '@/config' import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config' const PACKAGE_IDS_KEY = 'package-ids' +const BUNDLE_INFO_KEY = 'bundle-info' export type PluginPageProps = { plugins: React.ReactNode @@ -58,6 +60,18 @@ const PluginPage = ({ return '' } }, [searchParams]) + + const [dependencies, setDependencies] = useState([]) + const bundleInfo = useMemo(() => { + const info = searchParams.get(BUNDLE_INFO_KEY) + try { + return info ? JSON.parse(info) : undefined + } + catch (e) { + return undefined + } + }, [searchParams]) + const [isShowInstallFromMarketplace, { setTrue: showInstallFromMarketplace, setFalse: doHideInstallFromMarketplace, @@ -67,6 +81,7 @@ const PluginPage = ({ doHideInstallFromMarketplace() const url = new URL(window.location.href) url.searchParams.delete(PACKAGE_IDS_KEY) + url.searchParams.delete(BUNDLE_INFO_KEY) replace(url.toString()) } const [manifest, setManifest] = useState(null) @@ -83,10 +98,16 @@ const PluginPage = ({ icon: `${marketplaceApiPrefix}/plugins/${plugin.org}/${plugin.name}/icon`, }) showInstallFromMarketplace() + return + } + if (bundleInfo) { + const { data } = await fetchBundleInfoFromMarketPlace(bundleInfo) + setDependencies(data.version.dependencies) + showInstallFromMarketplace() } })() // eslint-disable-next-line react-hooks/exhaustive-deps - }, [packageId]) + }, [packageId, bundleInfo]) const { canManagement, @@ -211,6 +232,8 @@ const PluginPage = ({ diff --git a/web/service/plugins.ts b/web/service/plugins.ts index ef948966da..2857948860 100644 --- a/web/service/plugins.ts +++ b/web/service/plugins.ts @@ -1,6 +1,7 @@ import type { Fetcher } from 'swr' import { get, getMarketplace, post, upload } from './base' import type { + Dependency, InstallPackageResponse, Permissions, PluginDeclaration, @@ -66,6 +67,14 @@ export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) => return getMarketplace<{ data: { plugin: PluginManifestInMarket, version: { version: string } } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`) } +export const fetchBundleInfoFromMarketPlace = async ({ + org, + name, + version, +}: Record) => { + return getMarketplace<{ data: { version: { dependencies: Dependency[] } } }>(`/bundles/${org}/${name}/${version}`) +} + export const fetchMarketplaceCollections: Fetcher = ({ url }) => { return get(url) } diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 08469023d6..0fb1c956a3 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -110,6 +110,7 @@ export const useUploadGitHub = (payload: { queryFn: () => post('/workspaces/current/plugin/upload/github', { body: payload, }), + retry: 0, }) }