fix(plugin-install): support bundle marketplace dependency shape

This commit is contained in:
yyh
2026-03-09 17:07:27 +08:00
parent bab7bd5ecc
commit e845fa7e6a
3 changed files with 77 additions and 21 deletions

View File

@ -266,6 +266,29 @@ describe('useInstallMultiState', () => {
expect(result.current.plugins[1]).toBeDefined()
})
})
it('should resolve marketplace dependency from organization and plugin fields', async () => {
mockMarketplaceData = createMarketplaceApiData([0])
const params = createDefaultParams({
allPlugins: [
{
type: 'marketplace',
value: {
organization: 'test-org',
plugin: 'plugin-0',
version: '1.0.0',
},
} as GitHubItemAndMarketPlaceDependency,
] as Dependency[],
})
const { result } = renderHook(() => useInstallMultiState(params))
await waitFor(() => {
expect(result.current.plugins[0]).toBeDefined()
expect(result.current.errorIndexes).not.toContain(0)
})
})
})
// ==================== Error Handling ====================

View File

@ -20,6 +20,12 @@ type MarketplacePluginInfo = {
version?: string
}
type MarketplaceRequest = {
dslIndex: number
dependency: GitHubItemAndMarketPlaceDependency
info: MarketplacePluginInfo
}
export function getPluginKey(plugin: Plugin | undefined): string {
return `${plugin?.org || plugin?.author}/${plugin?.name}`
}
@ -40,6 +46,25 @@ function parseMarketplaceIdentifier(identifier?: string): MarketplacePluginInfo
return { organization, plugin, version }
}
function getMarketplacePluginInfo(
value: GitHubItemAndMarketPlaceDependency['value'],
): MarketplacePluginInfo | null {
const parsedInfo = parseMarketplaceIdentifier(
value.marketplace_plugin_unique_identifier || value.plugin_unique_identifier,
)
if (parsedInfo)
return parsedInfo
if (!value.organization || !value.plugin)
return null
return {
organization: value.organization,
plugin: value.plugin,
version: value.version,
}
}
function initPluginsFromDependencies(allPlugins: Dependency[]): (Plugin | undefined)[] {
if (!allPlugins.some(d => d.type === 'package'))
return []
@ -77,33 +102,35 @@ export function useInstallMultiState({
}, [])
}, [allPlugins])
const { marketplacePayloadByIdentifier, invalidMarketplaceIndexes } = useMemo(() => {
const { marketplaceRequests, invalidMarketplaceIndexes } = useMemo(() => {
return marketplacePlugins.reduce<{
marketplacePayloadByIdentifier: MarketplacePluginInfo[]
marketplaceRequests: MarketplaceRequest[]
invalidMarketplaceIndexes: number[]
}>((acc, d, marketplaceIndex) => {
const parsedIdentifier = parseMarketplaceIdentifier(
d.value.marketplace_plugin_unique_identifier || d.value.plugin_unique_identifier,
)
}>((acc, dependency, marketplaceIndex) => {
const dslIndex = marketPlaceInDSLIndex[marketplaceIndex]
if (parsedIdentifier)
acc.marketplacePayloadByIdentifier.push(parsedIdentifier)
else if (dslIndex !== undefined)
if (dslIndex === undefined)
return acc
const marketplaceInfo = getMarketplacePluginInfo(dependency.value)
if (!marketplaceInfo)
acc.invalidMarketplaceIndexes.push(dslIndex)
else
acc.marketplaceRequests.push({ dslIndex, dependency, info: marketplaceInfo })
return acc
}, {
marketplacePayloadByIdentifier: [],
marketplaceRequests: [],
invalidMarketplaceIndexes: [],
})
}, [marketPlaceInDSLIndex, marketplacePlugins])
// Marketplace data fetching: by unique identifier
// Marketplace data fetching: by normalized marketplace info
const {
isLoading: isFetchingById,
data: infoGetById,
error: infoByIdError,
} = useFetchPluginsInMarketPlaceByInfo(
marketplacePayloadByIdentifier,
marketplaceRequests.map(request => request.info),
)
// Derive marketplace plugin data and errors from API responses
@ -113,22 +140,26 @@ export function useInstallMultiState({
// Process "by ID" response
if (!isFetchingById && infoGetById?.data.list) {
const payloads = infoGetById.data.list
const pluginById = new Map(
infoGetById.data.list.map(item => [item.plugin.plugin_id, item.plugin]),
payloads.map(item => [item.plugin.plugin_id, item.plugin]),
)
marketPlaceInDSLIndex.forEach((index, i) => {
const dependency = marketplacePlugins[i]
const pluginId = (dependency?.value.marketplace_plugin_unique_identifier || dependency?.value.plugin_unique_identifier)?.split(':')[0]
const pluginInfo = pluginId ? pluginById.get(pluginId) : undefined
marketplaceRequests.forEach((request, requestIndex) => {
const pluginId = (
request.dependency.value.marketplace_plugin_unique_identifier
|| request.dependency.value.plugin_unique_identifier
)?.split(':')[0]
const pluginInfo = (pluginId ? pluginById.get(pluginId) : undefined) || payloads[requestIndex]?.plugin
if (pluginInfo) {
pluginMap.set(index, {
pluginMap.set(request.dslIndex, {
...pluginInfo,
from: dependency.type,
from: request.dependency.type,
version: pluginInfo.version || pluginInfo.latest_version,
})
}
else { errorSet.add(index) }
else { errorSet.add(request.dslIndex) }
})
}
@ -137,7 +168,7 @@ export function useInstallMultiState({
marketPlaceInDSLIndex.forEach(index => errorSet.add(index))
return { marketplacePluginMap: pluginMap, marketplaceErrorIndexes: errorSet }
}, [invalidMarketplaceIndexes, isFetchingById, infoGetById, infoByIdError, marketPlaceInDSLIndex, marketplacePlugins])
}, [invalidMarketplaceIndexes, isFetchingById, infoGetById, infoByIdError, marketPlaceInDSLIndex, marketplaceRequests])
// GitHub-fetched plugins and errors (imperative state from child callbacks)
const [githubPluginMap, setGithubPluginMap] = useState<Map<number, Plugin>>(() => new Map())

View File

@ -508,6 +508,8 @@ export type GitHubItemAndMarketPlaceDependency = {
type: 'github' | 'marketplace' | 'package'
value: {
repo?: string
organization?: string // from bundle marketplace dependency
plugin?: string // from bundle marketplace dependency
version?: string // from app DSL
package?: string // from app DSL
release?: string // from local package. same to the version