From b93be495302502f9b657101587b411d36cc2e9ba Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 22 Nov 2024 15:32:27 +0800 Subject: [PATCH 01/11] chore: support update show version --- web/app/components/plugins/plugin-page/index.tsx | 3 ++- web/app/components/plugins/types.ts | 2 +- web/service/plugins.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx index 486f4f47ce..26cf4b1659 100644 --- a/web/app/components/plugins/plugin-page/index.tsx +++ b/web/app/components/plugins/plugin-page/index.tsx @@ -76,9 +76,10 @@ const PluginPage = ({ await sleep(100) if (packageId) { const { data } = await fetchManifestFromMarketPlace(encodeURIComponent(packageId)) - const { plugin } = data + const { plugin, version } = data setManifest({ ...plugin, + version: version.version, icon: `${marketplaceApiPrefix}/plugins/${plugin.org}/${plugin.name}/icon`, }) showInstallFromMarketplace() diff --git a/web/app/components/plugins/types.ts b/web/app/components/plugins/types.ts index 5de8a6d2df..1ab127ec55 100644 --- a/web/app/components/plugins/types.ts +++ b/web/app/components/plugins/types.ts @@ -79,7 +79,7 @@ export type PluginManifestInMarket = { icon: string label: Record category: PluginType - version: string // TODO: wait api return current plugin version + version: string // conbine the other place to it latest_version: string brief: Record introduction: string diff --git a/web/service/plugins.ts b/web/service/plugins.ts index 28bf6c44f4..ef948966da 100644 --- a/web/service/plugins.ts +++ b/web/service/plugins.ts @@ -63,7 +63,7 @@ export const fetchManifest = async (uniqueIdentifier: string) => { } export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) => { - return getMarketplace<{ data: { plugin: PluginManifestInMarket } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`) + return getMarketplace<{ data: { plugin: PluginManifestInMarket, version: { version: string } } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`) } export const fetchMarketplaceCollections: Fetcher = ({ url }) => { From df049564e8a42bbd8472f8a5a6a628063db29e6b Mon Sep 17 00:00:00 2001 From: Joel Date: Mon, 25 Nov 2024 18:01:03 +0800 Subject: [PATCH 02/11] 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, }) } From 2041650ccad4fc35cd80de011ff90d8a41622c7e Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Tue, 26 Nov 2024 10:29:58 +0800 Subject: [PATCH 03/11] merge main --- web/app/styles/globals.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/app/styles/globals.css b/web/app/styles/globals.css index c76f8f51e9..8df48cc9e7 100644 --- a/web/app/styles/globals.css +++ b/web/app/styles/globals.css @@ -2,13 +2,8 @@ @tailwind base; @tailwind components; -<<<<<<< HEAD -@import "../../themes/light.css"; -@import "../../themes/dark.css"; -======= @import '../../themes/light.css'; @import '../../themes/dark.css'; ->>>>>>> main @import "../../themes/manual-light.css"; @import "../../themes/manual-dark.css"; From 00eb47384aaacb63795bde73f3a13cced983aec2 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Tue, 26 Nov 2024 10:31:39 +0800 Subject: [PATCH 04/11] merge main --- web/themes/dark.css | 8 -------- web/themes/manual-dark.css | 3 --- 2 files changed, 11 deletions(-) diff --git a/web/themes/dark.css b/web/themes/dark.css index 261e4db4cd..f0a7b521c6 100644 --- a/web/themes/dark.css +++ b/web/themes/dark.css @@ -336,11 +336,7 @@ html[data-theme="dark"] { --color-text-logo-text: #E9E9EC; --color-text-empty-state-icon: #C8CEDA4D; --color-text-inverted: #FFFFFF; -<<<<<<< HEAD - --color-text-inverted-dimm: #FFFFFFCC; -======= --color-text-inverted-dimmed: #FFFFFFCC; ->>>>>>> main --color-background-body: #1D1D20; --color-background-default-subtle: #222225; @@ -694,7 +690,6 @@ html[data-theme="dark"] { --color-third-party-LangChain: #FFFFFF; --color-third-party-Langfuse: #FFFFFF; -<<<<<<< HEAD --color-third-party-Github: #FFFFFF; --color-third-party-Github-tertiary: #C8CEDA99; @@ -702,7 +697,4 @@ html[data-theme="dark"] { --color-third-party-model-bg-openai: #121212; --color-third-party-model-bg-anthropic: #1D1917; --color-third-party-model-bg-default: #0B0B0E; -======= - --color-third-party-Github: #FFFFFF; ->>>>>>> main } \ No newline at end of file diff --git a/web/themes/manual-dark.css b/web/themes/manual-dark.css index c518cab72f..4e48cdbb16 100644 --- a/web/themes/manual-dark.css +++ b/web/themes/manual-dark.css @@ -2,9 +2,6 @@ html[data-theme="dark"] { --color-chatbot-bg: linear-gradient(180deg, rgba(34, 34, 37, 0.90) 0%, rgba(29, 29, 32, 0.90) 90.48%); --color-chat-bubble-bg: linear-gradient(180deg, rgba(200, 206, 218, 0.08) 0%, rgba(200, 206, 218, 0.02) 100%); --color-workflow-process-bg: linear-gradient(90deg, rgba(24, 24, 27, 0.25) 0%, rgba(24, 24, 27, 0.04) 100%); -<<<<<<< HEAD --color-marketplace-divider-bg: linear-gradient(90deg, rgba(200, 206, 218, 0.14) 0%, rgba(0, 0, 0, 0) 100%); --color-marketplace-plugin-empty: linear-gradient(180deg, rgba(0, 0, 0, 0.00) 0%, #222225 100%); -======= ->>>>>>> main } \ No newline at end of file From f47b32b26da3071253a11455bf590c4d126d0a17 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Tue, 26 Nov 2024 11:10:53 +0800 Subject: [PATCH 05/11] fix: dsl --- .../components/app/create-from-dsl-modal/index.tsx | 11 ++++++----- web/models/app.ts | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/web/app/components/app/create-from-dsl-modal/index.tsx b/web/app/components/app/create-from-dsl-modal/index.tsx index 07018838b4..08469715ed 100644 --- a/web/app/components/app/create-from-dsl-modal/index.tsx +++ b/web/app/components/app/create-from-dsl-modal/index.tsx @@ -25,7 +25,7 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { getRedirection } from '@/utils/app-redirection' import cn from '@/utils/classnames' -import { useMutationCheckDependenciesBeforeImportDSL } from '@/service/use-plugins' +import { useStore as usePluginDependencyStore } from '@/app/components/workflow/plugin-dependency/store' type CreateFromDSLModalProps = { show: boolean @@ -48,7 +48,6 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS const [fileContent, setFileContent] = useState() const [currentTab, setCurrentTab] = useState(activeTab) const [dslUrlValue, setDslUrlValue] = useState(dslUrl) - const { mutateAsync } = useMutationCheckDependenciesBeforeImportDSL() const [showErrorModal, setShowErrorModal] = useState(false) const [versions, setVersions] = useState<{ importedVersion: string; systemVersion: string }>() const [importId, setImportId] = useState() @@ -92,20 +91,22 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS mode: DSLImportMode.YAML_CONTENT, yaml_content: fileContent || '', }) - await mutateAsync({ dslString: fileContent }) } if (currentTab === CreateFromDSLModalTab.FROM_URL) { response = await importDSL({ mode: DSLImportMode.YAML_URL, yaml_url: dslUrlValue || '', }) - await mutateAsync({ url: dslUrlValue }) } if (!response) return - const { id, status, app_id, imported_dsl_version, current_dsl_version } = response + const { id, status, app_id, imported_dsl_version, current_dsl_version, leaked } = response + if (leaked?.length) { + const { setDependencies } = usePluginDependencyStore.getState() + setDependencies(leaked) + } if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) { if (onSuccess) onSuccess() diff --git a/web/models/app.ts b/web/models/app.ts index acb1c09622..5cf3f23e83 100644 --- a/web/models/app.ts +++ b/web/models/app.ts @@ -1,5 +1,6 @@ import type { LangFuseConfig, LangSmithConfig, TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type' import type { App, AppSSO, AppTemplate, SiteConfig } from '@/types/app' +import type { Dependency } from '@/app/components/plugins/types' /* export type App = { id: string @@ -87,6 +88,7 @@ export type DSLImportResponse = { current_dsl_version?: string imported_dsl_version?: string error: string + leaked: Dependency[] } export type AppSSOResponse = { enabled: AppSSO['enable_sso'] } From 4b77ced4adaab5c496355e68fc670697a0032639 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 26 Nov 2024 14:07:45 +0800 Subject: [PATCH 06/11] fix: not show from market bundle package icon --- .../install-plugin/install-bundle/item/package-item.tsx | 3 +++ .../install-plugin/install-bundle/ready-to-install.tsx | 3 +++ .../install-plugin/install-bundle/steps/install-multi.tsx | 4 ++++ .../plugins/install-plugin/install-bundle/steps/install.tsx | 3 +++ .../plugins/install-plugin/install-from-marketplace/index.tsx | 1 + 5 files changed, 14 insertions(+) diff --git a/web/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx b/web/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx index b649aada8f..97ee6b0de6 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/item/package-item.tsx @@ -11,12 +11,14 @@ type Props = { checked: boolean onCheckedChange: (plugin: Plugin) => void payload: PackageDependency + isFromMarketPlace?: boolean } const PackageItem: FC = ({ payload, checked, onCheckedChange, + isFromMarketPlace, }) => { if (!payload.value?.manifest) return @@ -27,6 +29,7 @@ const PackageItem: FC = ({ payload={plugin} checked={checked} onCheckedChange={onCheckedChange} + isFromMarketPlace={isFromMarketPlace} /> ) } diff --git a/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx b/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx index 0f5dda2395..b534f0c6b9 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/ready-to-install.tsx @@ -11,6 +11,7 @@ type Props = { onStepChange: (step: InstallStep) => void, allPlugins: Dependency[] onClose: () => void + isFromMarketPlace?: boolean } const ReadyToInstall: FC = ({ @@ -18,6 +19,7 @@ const ReadyToInstall: FC = ({ onStepChange, allPlugins, onClose, + isFromMarketPlace, }) => { const [installedPlugins, setInstalledPlugins] = useState([]) const [installStatus, setInstallStatus] = useState([]) @@ -33,6 +35,7 @@ const ReadyToInstall: FC = ({ allPlugins={allPlugins} onCancel={onClose} onInstalled={handleInstalled} + isFromMarketPlace={isFromMarketPlace} /> )} {step === InstallStep.installed && ( 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 445c8be9d9..e8bf71297d 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 @@ -14,6 +14,7 @@ type Props = { selectedPlugins: Plugin[] onSelect: (plugin: Plugin, selectedIndex: number) => void onLoadedAllPlugin: () => void + isFromMarketPlace?: boolean } const InstallByDSLList: FC = ({ @@ -21,6 +22,7 @@ const InstallByDSLList: FC = ({ selectedPlugins, onSelect, onLoadedAllPlugin, + isFromMarketPlace, }) => { // 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!)) @@ -171,12 +173,14 @@ const InstallByDSLList: FC = ({ ) } + // Local package return ( p.plugin_id === plugins[index]?.plugin_id)} onCheckedChange={handleSelect(index)} payload={d as PackageDependency} + isFromMarketPlace={isFromMarketPlace} /> ) }) diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx index 389cb3d9ca..223c561d84 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx @@ -14,12 +14,14 @@ type Props = { allPlugins: Dependency[] onInstalled: (plugins: Plugin[], installStatus: InstallStatusResponse[]) => void onCancel: () => void + isFromMarketPlace?: boolean } const Install: FC = ({ allPlugins, onInstalled, onCancel, + isFromMarketPlace, }) => { const { t } = useTranslation() const [selectedPlugins, setSelectedPlugins] = React.useState([]) @@ -75,6 +77,7 @@ const Install: FC = ({ selectedPlugins={selectedPlugins} onSelect={handleSelect} onLoadedAllPlugin={handleLoadedAllPlugin} + isFromMarketPlace={isFromMarketPlace} /> 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 5a3621995a..84668e0898 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 @@ -83,6 +83,7 @@ const InstallFromMarketplace: React.FC = ({ onStepChange={setStep} onClose={onClose} allPlugins={dependencies!} + isFromMarketPlace /> ) : (<> { From d40f0e645ca41c308158de905f46c864eb827418 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 26 Nov 2024 14:11:21 +0800 Subject: [PATCH 07/11] fix: install marketplace bundle title --- .../plugins/install-plugin/install-from-marketplace/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 84668e0898..f1126e09c8 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 @@ -41,12 +41,14 @@ const InstallFromMarketplace: React.FC = ({ // TODO: check installed in beta version. const getTitle = useCallback(() => { + if (isBundle && step === InstallStep.installed) + return t(`${i18nPrefix}.installComplete`) if (step === InstallStep.installed) return t(`${i18nPrefix}.installedSuccessfully`) if (step === InstallStep.installFailed) return t(`${i18nPrefix}.installFailed`) return t(`${i18nPrefix}.installPlugin`) - }, [step, t]) + }, [isBundle, step, t]) const handleInstalled = useCallback(() => { setStep(InstallStep.installed) From b8af4aead13ae8f1f6cc64ea508a1861fd792558 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 26 Nov 2024 14:38:43 +0800 Subject: [PATCH 08/11] fix: update version show problem --- .../plugins/plugin-detail-panel/detail-header.tsx | 10 +++++++++- .../plugins/update-plugin/from-market-place.tsx | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/web/app/components/plugins/plugin-detail-panel/detail-header.tsx b/web/app/components/plugins/plugin-detail-panel/detail-header.tsx index 767366938f..75239a424f 100644 --- a/web/app/components/plugins/plugin-detail-panel/detail-header.tsx +++ b/web/app/components/plugins/plugin-detail-panel/detail-header.tsx @@ -201,7 +201,15 @@ const DetailHeader = ({ } /> {(hasNewVersion || isFromGitHub) && ( - + )}
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 071b143115..e4abd32aff 100644 --- a/web/app/components/plugins/update-plugin/from-market-place.tsx +++ b/web/app/components/plugins/update-plugin/from-market-place.tsx @@ -89,6 +89,7 @@ const UpdatePluginModal: FC = ({ }) onSave() } + // eslint-disable-next-line unused-imports/no-unused-vars catch (e) { setUploadStep(UploadStep.notStarted) } From e908ecab8fc2f84868d3887092eb0453821b4a98 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 27 Nov 2024 10:50:39 +0800 Subject: [PATCH 09/11] fix: add ui --- .../components/datasets/documents/detail/new-segment-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/datasets/documents/detail/new-segment-modal.tsx b/web/app/components/datasets/documents/detail/new-segment-modal.tsx index dae9cf19fb..4c51779f9c 100644 --- a/web/app/components/datasets/documents/detail/new-segment-modal.tsx +++ b/web/app/components/datasets/documents/detail/new-segment-modal.tsx @@ -135,7 +135,7 @@ const NewSegmentModal: FC = ({
setKeywords(newKeywords)} />
-
+
+
diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 2eccb38e47..ecd35876e7 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -72,7 +72,6 @@ import SyncingDataModal from './syncing-data-modal' import UpdateDSLModal from './update-dsl-modal' import DSLExportConfirmModal from './dsl-export-confirm-modal' import LimitTips from './limit-tips' -import PluginDependency from './plugin-dependency' import { useStore, useWorkflowStore, @@ -327,7 +326,6 @@ const Workflow: FC = memo(({ /> ) } - { const dependencies = useStore(s => s.dependencies) - const handleCancelInstallBundle = useCallback(() => { - const { setDependencies } = useStore.getState() - setDependencies([]) - }, []) + const [step, setStep] = useState(InstallStep.readyToInstall) + + const { t } = useTranslation() + const getTitle = useCallback(() => { + if (step === InstallStep.uploadFailed) + return t(`${i18nPrefix}.uploadFailed`) + if (step === InstallStep.installed) + return t(`${i18nPrefix}.installComplete`) + + return t(`${i18nPrefix}.installPlugin`) + }, [step, t]) if (!dependencies.length) return null return (
- +
+ {getTitle()} +
+
+ {}} />
) diff --git a/web/app/components/workflow/update-dsl-modal.tsx b/web/app/components/workflow/update-dsl-modal.tsx index 9bd1113749..a750ebe21e 100644 --- a/web/app/components/workflow/update-dsl-modal.tsx +++ b/web/app/components/workflow/update-dsl-modal.tsx @@ -38,6 +38,8 @@ import { ToastContext } from '@/app/components/base/toast' import { useEventEmitterContextContext } from '@/context/event-emitter' import { useStore as useAppStore } from '@/app/components/app/store' import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants' +import { useStore as usePluginDependencyStore } from '@/app/components/workflow/plugin-dependency/store' +import PluginDependency from '@/app/components/workflow/plugin-dependency' type UpdateDSLModalProps = { onCancel: () => void @@ -135,7 +137,11 @@ const UpdateDSLModal = ({ if (appDetail && fileContent) { setLoading(true) const response = await importDSL({ mode: DSLImportMode.YAML_CONTENT, yaml_content: fileContent, app_id: appDetail.id }) - const { id, status, app_id, imported_dsl_version, current_dsl_version } = response + const { id, status, app_id, imported_dsl_version, current_dsl_version, leaked_dependencies } = response + if (leaked_dependencies?.length) { + const { setDependencies } = usePluginDependencyStore.getState() + setDependencies(leaked_dependencies) + } if (status === DSLImportStatus.COMPLETED || status === DSLImportStatus.COMPLETED_WITH_WARNINGS) { if (!app_id) { notify({ type: 'error', message: t('workflow.common.importFailure') }) @@ -283,6 +289,7 @@ const UpdateDSLModal = ({
{t('app.newApp.appCreateDSLErrorPart4')}{versions?.systemVersion}
+
diff --git a/web/models/app.ts b/web/models/app.ts index 5cf3f23e83..81a8575dd8 100644 --- a/web/models/app.ts +++ b/web/models/app.ts @@ -88,7 +88,7 @@ export type DSLImportResponse = { current_dsl_version?: string imported_dsl_version?: string error: string - leaked: Dependency[] + leaked_dependencies: Dependency[] } export type AppSSOResponse = { enabled: AppSSO['enable_sso'] } diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 0fb1c956a3..9072810426 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -24,7 +24,6 @@ import { useQuery, useQueryClient, } from '@tanstack/react-query' -import { useStore as usePluginDependencyStore } from '@/app/components/workflow/plugin-dependency/store' import { useInvalidateAllBuiltInTools } from './use-tools' const NAME_SPACE = 'plugins' @@ -324,36 +323,6 @@ export const useMutationClearAllTaskPlugin = () => { }) } -export const useMutationCheckDependenciesBeforeImportDSL = () => { - const mutation = useMutation({ - mutationFn: ({ dslString, url }: { dslString?: string, url?: string }) => { - if (url) { - return post<{ leaked: Dependency[] }>( - '/apps/import/url/dependencies/check', - { - body: { - url, - }, - }, - ) - } - return post<{ leaked: Dependency[] }>( - '/apps/import/dependencies/check', - { - body: { - data: dslString, - }, - }) - }, - onSuccess: (data) => { - const { setDependencies } = usePluginDependencyStore.getState() - setDependencies(data.leaked || []) - }, - }) - - return mutation -} - export const useDownloadPlugin = (info: { organization: string; pluginName: string; version: string }, needDownload: boolean) => { return useQuery({ queryKey: [NAME_SPACE, 'downloadPlugin', info], From d4cda69b0e3197a8d4b60f4526702f40596ae246 Mon Sep 17 00:00:00 2001 From: StyleZhang Date: Wed, 27 Nov 2024 16:14:15 +0800 Subject: [PATCH 11/11] feat: marketplace add exclude --- web/app/(commonLayout)/plugins/page.tsx | 2 +- .../plugins/marketplace/context.tsx | 33 +++++++++-- .../components/plugins/marketplace/hooks.ts | 6 +- .../components/plugins/marketplace/index.tsx | 12 +++- .../components/plugins/marketplace/types.ts | 2 + .../components/plugins/marketplace/utils.ts | 56 ++++--------------- web/app/components/tools/marketplace/hooks.ts | 26 ++++++--- web/service/use-plugins.ts | 6 +- 8 files changed, 81 insertions(+), 62 deletions(-) diff --git a/web/app/(commonLayout)/plugins/page.tsx b/web/app/(commonLayout)/plugins/page.tsx index 516cc138a2..f44ff6522a 100644 --- a/web/app/(commonLayout)/plugins/page.tsx +++ b/web/app/(commonLayout)/plugins/page.tsx @@ -8,7 +8,7 @@ const PluginList = async () => { return ( } - marketplace={} + marketplace={} /> ) } diff --git a/web/app/components/plugins/marketplace/context.tsx b/web/app/components/plugins/marketplace/context.tsx index 4b692cac28..57e3dae420 100644 --- a/web/app/components/plugins/marketplace/context.tsx +++ b/web/app/components/plugins/marketplace/context.tsx @@ -6,6 +6,7 @@ import type { import { useCallback, useEffect, + useMemo, useRef, useState, } from 'react' @@ -30,6 +31,7 @@ import { useMarketplacePlugins, } from './hooks' import { getMarketplaceListCondition } from './utils' +import { useInstalledPluginList } from '@/service/use-plugins' export type MarketplaceContextValue = { intersected: boolean @@ -74,6 +76,7 @@ export const MarketplaceContext = createContext({ type MarketplaceContextProviderProps = { children: ReactNode searchParams?: SearchParams + shouldExclude?: boolean } export function useMarketplaceContext(selector: (value: MarketplaceContextValue) => any) { @@ -83,7 +86,13 @@ export function useMarketplaceContext(selector: (value: MarketplaceContextValue) export const MarketplaceContextProvider = ({ children, searchParams, + shouldExclude, }: MarketplaceContextProviderProps) => { + const { data, isSuccess } = useInstalledPluginList(!shouldExclude) + const exclude = useMemo(() => { + if (shouldExclude) + return data?.plugins.map(plugin => plugin.plugin_id) + }, [data?.plugins, shouldExclude]) const queryFromSearchParams = searchParams?.q || '' const tagsFromSearchParams = searchParams?.tags ? getValidTagKeys(searchParams.tags.split(',')) : [] const hasValidTags = !!tagsFromSearchParams.length @@ -125,8 +134,15 @@ export const MarketplaceContextProvider = ({ }) history.pushState({}, '', `/${searchParams?.language ? `?language=${searchParams?.language}` : ''}`) } + else { + if (shouldExclude && isSuccess) { + queryMarketplaceCollectionsAndPlugins({ + exclude, + }) + } + } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [queryPlugins]) + }, [queryPlugins, queryMarketplaceCollectionsAndPlugins, isSuccess, exclude]) const handleSearchPluginTextChange = useCallback((text: string) => { setSearchPluginText(text) @@ -136,6 +152,7 @@ export const MarketplaceContextProvider = ({ queryMarketplaceCollectionsAndPlugins({ category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current, condition: getMarketplaceListCondition(activePluginTypeRef.current), + exclude, }) resetPlugins() @@ -148,8 +165,9 @@ export const MarketplaceContextProvider = ({ tags: filterPluginTagsRef.current, sortBy: sortRef.current.sortBy, sortOrder: sortRef.current.sortOrder, + exclude, }) - }, [queryPluginsWithDebounced, queryMarketplaceCollectionsAndPlugins, resetPlugins]) + }, [queryPluginsWithDebounced, queryMarketplaceCollectionsAndPlugins, resetPlugins, exclude]) const handleFilterPluginTagsChange = useCallback((tags: string[]) => { setFilterPluginTags(tags) @@ -159,6 +177,7 @@ export const MarketplaceContextProvider = ({ queryMarketplaceCollectionsAndPlugins({ category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current, condition: getMarketplaceListCondition(activePluginTypeRef.current), + exclude, }) resetPlugins() @@ -171,8 +190,9 @@ export const MarketplaceContextProvider = ({ tags, sortBy: sortRef.current.sortBy, sortOrder: sortRef.current.sortOrder, + exclude, }) - }, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins]) + }, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude]) const handleActivePluginTypeChange = useCallback((type: string) => { setActivePluginType(type) @@ -182,6 +202,7 @@ export const MarketplaceContextProvider = ({ queryMarketplaceCollectionsAndPlugins({ category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type, condition: getMarketplaceListCondition(type), + exclude, }) resetPlugins() @@ -194,8 +215,9 @@ export const MarketplaceContextProvider = ({ tags: filterPluginTagsRef.current, sortBy: sortRef.current.sortBy, sortOrder: sortRef.current.sortOrder, + exclude, }) - }, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins]) + }, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude]) const handleSortChange = useCallback((sort: PluginsSort) => { setSort(sort) @@ -207,8 +229,9 @@ export const MarketplaceContextProvider = ({ tags: filterPluginTagsRef.current, sortBy: sortRef.current.sortBy, sortOrder: sortRef.current.sortOrder, + exclude, }) - }, [queryPlugins]) + }, [queryPlugins, exclude]) return ( { const [isLoading, setIsLoading] = useState(false) @@ -55,7 +57,7 @@ export const useMarketplacePlugins = () => { mutate(pluginsSearchParams) }, [mutate]) - const { run: queryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams) => { + const { run: queryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams: PluginsSearchParams) => { mutate(pluginsSearchParams) }, { wait: 500, diff --git a/web/app/components/plugins/marketplace/index.tsx b/web/app/components/plugins/marketplace/index.tsx index 5afb8c31ae..9f8bbb2e76 100644 --- a/web/app/components/plugins/marketplace/index.tsx +++ b/web/app/components/plugins/marketplace/index.tsx @@ -11,18 +11,26 @@ import { TanstackQueryIniter } from '@/context/query-client' type MarketplaceProps = { locale: string showInstallButton?: boolean + shouldExclude?: boolean searchParams?: SearchParams } const Marketplace = async ({ locale, showInstallButton = true, + shouldExclude, searchParams, }: MarketplaceProps) => { - const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins() + let marketplaceCollections: any = [] + let marketplaceCollectionPluginsMap = {} + if (!shouldExclude) { + const marketplaceCollectionsAndPluginsData = await getMarketplaceCollectionsAndPlugins() + marketplaceCollections = marketplaceCollectionsAndPluginsData.marketplaceCollections + marketplaceCollectionPluginsMap = marketplaceCollectionsAndPluginsData.marketplaceCollectionPluginsMap + } return ( - + diff --git a/web/app/components/plugins/marketplace/types.ts b/web/app/components/plugins/marketplace/types.ts index 58424d6c68..844ced0e00 100644 --- a/web/app/components/plugins/marketplace/types.ts +++ b/web/app/components/plugins/marketplace/types.ts @@ -27,6 +27,7 @@ export type PluginsSearchParams = { sortOrder?: string category?: string tags?: string[] + exclude?: string[] } export type PluginsSort = { @@ -37,6 +38,7 @@ export type PluginsSort = { export type CollectionsAndPluginsSearchParams = { category?: string condition?: string + exclude?: string[] } export type SearchParams = { diff --git a/web/app/components/plugins/marketplace/utils.ts b/web/app/components/plugins/marketplace/utils.ts index c9f77318f7..7252b9d315 100644 --- a/web/app/components/plugins/marketplace/utils.ts +++ b/web/app/components/plugins/marketplace/utils.ts @@ -3,7 +3,6 @@ import { PluginType } from '@/app/components/plugins/types' import type { CollectionsAndPluginsSearchParams, MarketplaceCollection, - PluginsSearchParams, } from '@/app/components/plugins/marketplace/types' import { MARKETPLACE_API_PREFIX } from '@/config' @@ -22,10 +21,18 @@ export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAnd const marketplaceCollectionsDataJson = await marketplaceCollectionsData.json() marketplaceCollections = marketplaceCollectionsDataJson.data.collections await Promise.all(marketplaceCollections.map(async (collection: MarketplaceCollection) => { - let url = `${MARKETPLACE_API_PREFIX}/collections/${collection.name}/plugins?page=1&page_size=100` - if (query?.category) - url += `&category=${query.category}` - const marketplaceCollectionPluginsData = await globalThis.fetch(url, { cache: 'no-store' }) + const url = `${MARKETPLACE_API_PREFIX}/collections/${collection.name}/plugins` + const marketplaceCollectionPluginsData = await globalThis.fetch( + url, + { + cache: 'no-store', + method: 'POST', + body: JSON.stringify({ + category: query?.category, + exclude: query?.exclude, + }), + }, + ) const marketplaceCollectionPluginsDataJson = await marketplaceCollectionPluginsData.json() const plugins = marketplaceCollectionPluginsDataJson.data.plugins.map((plugin: Plugin) => { return { @@ -49,45 +56,6 @@ export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAnd } } -export const getMarketplacePlugins = async (query: PluginsSearchParams) => { - let marketplacePlugins = [] as Plugin[] - try { - const marketplacePluginsData = await globalThis.fetch( - `${MARKETPLACE_API_PREFIX}/plugins/search/basic`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - page: 1, - page_size: 10, - query: query.query, - sort_by: query.sortBy, - sort_order: query.sortOrder, - category: query.category, - tags: query.tags, - }), - }, - ) - const marketplacePluginsDataJson = await marketplacePluginsData.json() - marketplacePlugins = marketplacePluginsDataJson.data.plugins.map((plugin: Plugin) => { - return { - ...plugin, - icon: getPluginIconInMarketplace(plugin), - } - }) - } - // eslint-disable-next-line unused-imports/no-unused-vars - catch (e) { - marketplacePlugins = [] - } - - return { - marketplacePlugins, - } -} - export const getMarketplaceListCondition = (pluginType: string) => { if (pluginType === PluginType.tool) return 'category=tool' diff --git a/web/app/components/tools/marketplace/hooks.ts b/web/app/components/tools/marketplace/hooks.ts index 3aec42be75..e29920ab29 100644 --- a/web/app/components/tools/marketplace/hooks.ts +++ b/web/app/components/tools/marketplace/hooks.ts @@ -1,5 +1,6 @@ import { useEffect, + useMemo, } from 'react' import { useMarketplaceCollectionsAndPlugins, @@ -7,8 +8,14 @@ import { } from '@/app/components/plugins/marketplace/hooks' import { PluginType } from '@/app/components/plugins/types' import { getMarketplaceListCondition } from '@/app/components/plugins/marketplace/utils' +import { useAllToolProviders } from '@/service/use-tools' export const useMarketplace = (searchPluginText: string, filterPluginTags: string[]) => { + const { data: toolProvidersData, isSuccess } = useAllToolProviders() + const exclude = useMemo(() => { + if (isSuccess) + return toolProvidersData?.filter(toolProvider => !!toolProvider.plugin_id).map(toolProvider => toolProvider.plugin_id!) + }, [isSuccess, toolProvidersData]) const { isLoading, marketplaceCollections, @@ -24,12 +31,13 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin } = useMarketplacePlugins() useEffect(() => { - if (searchPluginText || filterPluginTags.length) { + if ((searchPluginText || filterPluginTags.length) && isSuccess) { if (searchPluginText) { queryPluginsWithDebounced({ category: PluginType.tool, query: searchPluginText, tags: filterPluginTags, + exclude, }) return } @@ -37,16 +45,20 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin category: PluginType.tool, query: searchPluginText, tags: filterPluginTags, + exclude, }) } else { - queryMarketplaceCollectionsAndPlugins({ - category: PluginType.tool, - condition: getMarketplaceListCondition(PluginType.tool), - }) - resetPlugins() + if (isSuccess) { + queryMarketplaceCollectionsAndPlugins({ + category: PluginType.tool, + condition: getMarketplaceListCondition(PluginType.tool), + exclude, + }) + resetPlugins() + } } - }, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, resetPlugins]) + }, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, resetPlugins, exclude, isSuccess]) return { isLoading: isLoading || isPluginsLoading, diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 9072810426..9bdf63c5c5 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -29,10 +29,12 @@ import { useInvalidateAllBuiltInTools } from './use-tools' const NAME_SPACE = 'plugins' const useInstalledPluginListKey = [NAME_SPACE, 'installedPluginList'] -export const useInstalledPluginList = () => { +export const useInstalledPluginList = (disable?: boolean) => { return useQuery({ queryKey: useInstalledPluginListKey, queryFn: () => get('/workspaces/current/plugin/list'), + enabled: !disable, + initialData: !disable ? undefined : { plugins: [] }, }) } @@ -225,6 +227,7 @@ export const useMutationPluginsFromMarketplace = () => { sortOrder, category, tags, + exclude, } = pluginsSearchParams return postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/search/basic', { body: { @@ -235,6 +238,7 @@ export const useMutationPluginsFromMarketplace = () => { sort_order: sortOrder, category: category !== 'all' ? category : '', tags, + exclude, }, }) },