mirror of
https://github.com/langgenius/dify.git
synced 2026-04-27 11:06:46 +08:00
feat: support install bundle from marketplace
This commit is contained in:
parent
b93be49530
commit
df049564e8
@ -22,8 +22,10 @@ const InstallByDSLList: FC<Props> = ({
|
|||||||
onSelect,
|
onSelect,
|
||||||
onLoadedAllPlugin,
|
onLoadedAllPlugin,
|
||||||
}) => {
|
}) => {
|
||||||
const { isLoading: isFetchingMarketplaceDataFromDSL, data: marketplaceFromDSLRes } = useFetchPluginsInMarketPlaceByIds(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value.plugin_unique_identifier!))
|
// DSL has id, to get plugin info to show more info
|
||||||
const { isLoading: isFetchingMarketplaceDataFromLocal, data: marketplaceResFromLocalRes } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map(d => (d as GitHubItemAndMarketPlaceDependency).value!))
|
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 [plugins, doSetPlugins] = useState<(Plugin | undefined)[]>((() => {
|
||||||
const hasLocalPackage = allPlugins.some(d => d.type === 'package')
|
const hasLocalPackage = allPlugins.some(d => d.type === 'package')
|
||||||
if (!hasLocalPackage)
|
if (!hasLocalPackage)
|
||||||
@ -75,8 +77,8 @@ const InstallByDSLList: FC<Props> = ({
|
|||||||
}, [allPlugins])
|
}, [allPlugins])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFetchingMarketplaceDataFromDSL && marketplaceFromDSLRes?.data.plugins) {
|
if (!isFetchingMarketplaceDataById && infoGetById?.data.plugins) {
|
||||||
const payloads = marketplaceFromDSLRes?.data.plugins
|
const payloads = infoGetById?.data.plugins
|
||||||
const failedIndex: number[] = []
|
const failedIndex: number[] = []
|
||||||
const nextPlugins = produce(pluginsRef.current, (draft) => {
|
const nextPlugins = produce(pluginsRef.current, (draft) => {
|
||||||
marketPlaceInDSLIndex.forEach((index, i) => {
|
marketPlaceInDSLIndex.forEach((index, i) => {
|
||||||
@ -92,11 +94,11 @@ const InstallByDSLList: FC<Props> = ({
|
|||||||
setErrorIndexes([...errorIndexes, ...failedIndex])
|
setErrorIndexes([...errorIndexes, ...failedIndex])
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [isFetchingMarketplaceDataFromDSL])
|
}, [isFetchingMarketplaceDataById])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFetchingMarketplaceDataFromLocal && marketplaceResFromLocalRes?.data.list) {
|
if (!isFetchingDataByMeta && infoByMeta?.data.list) {
|
||||||
const payloads = marketplaceResFromLocalRes?.data.list
|
const payloads = infoByMeta?.data.list
|
||||||
const failedIndex: number[] = []
|
const failedIndex: number[] = []
|
||||||
const nextPlugins = produce(pluginsRef.current, (draft) => {
|
const nextPlugins = produce(pluginsRef.current, (draft) => {
|
||||||
marketPlaceInDSLIndex.forEach((index, i) => {
|
marketPlaceInDSLIndex.forEach((index, i) => {
|
||||||
@ -117,7 +119,15 @@ const InstallByDSLList: FC<Props> = ({
|
|||||||
setErrorIndexes([...errorIndexes, ...failedIndex])
|
setErrorIndexes([...errorIndexes, ...failedIndex])
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// 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
|
const isLoadedAllData = (plugins.filter(p => !!p).length + errorIndexes.length) === allPlugins.length
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||||||
updateModelProviders()
|
updateModelProviders()
|
||||||
if (PluginType.tool.includes(manifest.category))
|
if (PluginType.tool.includes(manifest.category))
|
||||||
invalidateAllToolProviders()
|
invalidateAllToolProviders()
|
||||||
}, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest.category, updateModelProviders])
|
}, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest, updateModelProviders])
|
||||||
|
|
||||||
const handleFailed = useCallback((errorMsg?: string) => {
|
const handleFailed = useCallback((errorMsg?: string) => {
|
||||||
setStep(InstallStep.installFailed)
|
setStep(InstallStep.installFailed)
|
||||||
@ -76,17 +76,6 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||||||
{getTitle()}
|
{getTitle()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{
|
|
||||||
step === InstallStep.readyToInstall && (
|
|
||||||
<Install
|
|
||||||
uniqueIdentifier={uniqueIdentifier}
|
|
||||||
payload={manifest!}
|
|
||||||
onCancel={onClose}
|
|
||||||
onInstalled={handleInstalled}
|
|
||||||
onFailed={handleFailed}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
isBundle ? (
|
isBundle ? (
|
||||||
<ReadyToInstallBundle
|
<ReadyToInstallBundle
|
||||||
@ -95,17 +84,32 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
allPlugins={dependencies!}
|
allPlugins={dependencies!}
|
||||||
/>
|
/>
|
||||||
) : ([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
|
) : (<>
|
||||||
<Installed
|
{
|
||||||
payload={manifest!}
|
step === InstallStep.readyToInstall && (
|
||||||
isMarketPayload
|
<Install
|
||||||
isFailed={step === InstallStep.installFailed}
|
uniqueIdentifier={uniqueIdentifier}
|
||||||
errMsg={errorMsg}
|
payload={manifest!}
|
||||||
onCancel={onSuccess}
|
onCancel={onClose}
|
||||||
/>
|
onInstalled={handleInstalled}
|
||||||
|
onFailed={handleFailed}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{
|
||||||
|
[InstallStep.installed, InstallStep.installFailed].includes(step) && (
|
||||||
|
<Installed
|
||||||
|
payload={manifest!}
|
||||||
|
isMarketPayload
|
||||||
|
isFailed={step === InstallStep.installFailed}
|
||||||
|
errMsg={errorMsg}
|
||||||
|
onCancel={onSuccess}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Modal>
|
</Modal >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ const Installed: FC<Props> = ({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}</>)
|
}</>)
|
||||||
}, [payload.latest_version, supportCheckInstalled])
|
}, [payload.latest_version, payload.version, supportCheckInstalled])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -28,13 +28,15 @@ import {
|
|||||||
useRouter,
|
useRouter,
|
||||||
useSearchParams,
|
useSearchParams,
|
||||||
} from 'next/navigation'
|
} from 'next/navigation'
|
||||||
|
import type { Dependency } from '../types'
|
||||||
import type { PluginDeclaration, PluginManifestInMarket } from '../types'
|
import type { PluginDeclaration, PluginManifestInMarket } from '../types'
|
||||||
import { sleep } from '@/utils'
|
import { sleep } from '@/utils'
|
||||||
import { fetchManifestFromMarketPlace } from '@/service/plugins'
|
import { fetchBundleInfoFromMarketPlace, fetchManifestFromMarketPlace } from '@/service/plugins'
|
||||||
import { marketplaceApiPrefix } from '@/config'
|
import { marketplaceApiPrefix } from '@/config'
|
||||||
import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config'
|
import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config'
|
||||||
|
|
||||||
const PACKAGE_IDS_KEY = 'package-ids'
|
const PACKAGE_IDS_KEY = 'package-ids'
|
||||||
|
const BUNDLE_INFO_KEY = 'bundle-info'
|
||||||
|
|
||||||
export type PluginPageProps = {
|
export type PluginPageProps = {
|
||||||
plugins: React.ReactNode
|
plugins: React.ReactNode
|
||||||
@ -58,6 +60,18 @@ const PluginPage = ({
|
|||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}, [searchParams])
|
}, [searchParams])
|
||||||
|
|
||||||
|
const [dependencies, setDependencies] = useState<Dependency[]>([])
|
||||||
|
const bundleInfo = useMemo(() => {
|
||||||
|
const info = searchParams.get(BUNDLE_INFO_KEY)
|
||||||
|
try {
|
||||||
|
return info ? JSON.parse(info) : undefined
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}, [searchParams])
|
||||||
|
|
||||||
const [isShowInstallFromMarketplace, {
|
const [isShowInstallFromMarketplace, {
|
||||||
setTrue: showInstallFromMarketplace,
|
setTrue: showInstallFromMarketplace,
|
||||||
setFalse: doHideInstallFromMarketplace,
|
setFalse: doHideInstallFromMarketplace,
|
||||||
@ -67,6 +81,7 @@ const PluginPage = ({
|
|||||||
doHideInstallFromMarketplace()
|
doHideInstallFromMarketplace()
|
||||||
const url = new URL(window.location.href)
|
const url = new URL(window.location.href)
|
||||||
url.searchParams.delete(PACKAGE_IDS_KEY)
|
url.searchParams.delete(PACKAGE_IDS_KEY)
|
||||||
|
url.searchParams.delete(BUNDLE_INFO_KEY)
|
||||||
replace(url.toString())
|
replace(url.toString())
|
||||||
}
|
}
|
||||||
const [manifest, setManifest] = useState<PluginDeclaration | PluginManifestInMarket | null>(null)
|
const [manifest, setManifest] = useState<PluginDeclaration | PluginManifestInMarket | null>(null)
|
||||||
@ -83,10 +98,16 @@ const PluginPage = ({
|
|||||||
icon: `${marketplaceApiPrefix}/plugins/${plugin.org}/${plugin.name}/icon`,
|
icon: `${marketplaceApiPrefix}/plugins/${plugin.org}/${plugin.name}/icon`,
|
||||||
})
|
})
|
||||||
showInstallFromMarketplace()
|
showInstallFromMarketplace()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (bundleInfo) {
|
||||||
|
const { data } = await fetchBundleInfoFromMarketPlace(bundleInfo)
|
||||||
|
setDependencies(data.version.dependencies)
|
||||||
|
showInstallFromMarketplace()
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [packageId])
|
}, [packageId, bundleInfo])
|
||||||
|
|
||||||
const {
|
const {
|
||||||
canManagement,
|
canManagement,
|
||||||
@ -211,6 +232,8 @@ const PluginPage = ({
|
|||||||
<InstallFromMarketplace
|
<InstallFromMarketplace
|
||||||
manifest={manifest! as PluginManifestInMarket}
|
manifest={manifest! as PluginManifestInMarket}
|
||||||
uniqueIdentifier={packageId}
|
uniqueIdentifier={packageId}
|
||||||
|
isBundle={!!bundleInfo}
|
||||||
|
dependencies={dependencies}
|
||||||
onClose={hideInstallFromMarketplace}
|
onClose={hideInstallFromMarketplace}
|
||||||
onSuccess={hideInstallFromMarketplace}
|
onSuccess={hideInstallFromMarketplace}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { Fetcher } from 'swr'
|
import type { Fetcher } from 'swr'
|
||||||
import { get, getMarketplace, post, upload } from './base'
|
import { get, getMarketplace, post, upload } from './base'
|
||||||
import type {
|
import type {
|
||||||
|
Dependency,
|
||||||
InstallPackageResponse,
|
InstallPackageResponse,
|
||||||
Permissions,
|
Permissions,
|
||||||
PluginDeclaration,
|
PluginDeclaration,
|
||||||
@ -66,6 +67,14 @@ export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) =>
|
|||||||
return getMarketplace<{ data: { plugin: PluginManifestInMarket, version: { version: string } } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`)
|
return getMarketplace<{ data: { plugin: PluginManifestInMarket, version: { version: string } } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchBundleInfoFromMarketPlace = async ({
|
||||||
|
org,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
}: Record<string, string>) => {
|
||||||
|
return getMarketplace<{ data: { version: { dependencies: Dependency[] } } }>(`/bundles/${org}/${name}/${version}`)
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchMarketplaceCollections: Fetcher<MarketplaceCollectionsResponse, { url: string; }> = ({ url }) => {
|
export const fetchMarketplaceCollections: Fetcher<MarketplaceCollectionsResponse, { url: string; }> = ({ url }) => {
|
||||||
return get<MarketplaceCollectionsResponse>(url)
|
return get<MarketplaceCollectionsResponse>(url)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,6 +110,7 @@ export const useUploadGitHub = (payload: {
|
|||||||
queryFn: () => post<uploadGitHubResponse>('/workspaces/current/plugin/upload/github', {
|
queryFn: () => post<uploadGitHubResponse>('/workspaces/current/plugin/upload/github', {
|
||||||
body: payload,
|
body: payload,
|
||||||
}),
|
}),
|
||||||
|
retry: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user