feat: support install bundle from marketplace

This commit is contained in:
Joel 2024-11-25 18:01:03 +08:00
parent b93be49530
commit df049564e8
6 changed files with 79 additions and 32 deletions

View File

@ -22,8 +22,10 @@ const InstallByDSLList: FC<Props> = ({
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<Props> = ({
}, [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<Props> = ({
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<Props> = ({
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(() => {

View File

@ -55,7 +55,7 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
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<InstallFromMarketplaceProps> = ({
{getTitle()}
</div>
</div>
{
step === InstallStep.readyToInstall && (
<Install
uniqueIdentifier={uniqueIdentifier}
payload={manifest!}
onCancel={onClose}
onInstalled={handleInstalled}
onFailed={handleFailed}
/>
)
}
{
isBundle ? (
<ReadyToInstallBundle
@ -95,17 +84,32 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
onClose={onClose}
allPlugins={dependencies!}
/>
) : ([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
<Installed
payload={manifest!}
isMarketPayload
isFailed={step === InstallStep.installFailed}
errMsg={errorMsg}
onCancel={onSuccess}
/>
) : (<>
{
step === InstallStep.readyToInstall && (
<Install
uniqueIdentifier={uniqueIdentifier}
payload={manifest!}
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 >
)
}

View File

@ -94,7 +94,7 @@ const Installed: FC<Props> = ({
</>
)
}</>)
}, [payload.latest_version, supportCheckInstalled])
}, [payload.latest_version, payload.version, supportCheckInstalled])
return (
<>

View File

@ -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<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, {
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<PluginDeclaration | PluginManifestInMarket | null>(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 = ({
<InstallFromMarketplace
manifest={manifest! as PluginManifestInMarket}
uniqueIdentifier={packageId}
isBundle={!!bundleInfo}
dependencies={dependencies}
onClose={hideInstallFromMarketplace}
onSuccess={hideInstallFromMarketplace}
/>

View File

@ -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<string, string>) => {
return getMarketplace<{ data: { version: { dependencies: Dependency[] } } }>(`/bundles/${org}/${name}/${version}`)
}
export const fetchMarketplaceCollections: Fetcher<MarketplaceCollectionsResponse, { url: string; }> = ({ url }) => {
return get<MarketplaceCollectionsResponse>(url)
}

View File

@ -110,6 +110,7 @@ export const useUploadGitHub = (payload: {
queryFn: () => post<uploadGitHubResponse>('/workspaces/current/plugin/upload/github', {
body: payload,
}),
retry: 0,
})
}