fix: install bunlde support update

This commit is contained in:
Joel 2024-11-28 18:26:07 +08:00
parent 6a500edf4d
commit 32619bd05e
10 changed files with 141 additions and 47 deletions

View File

@ -2,14 +2,9 @@
import type { FC } from 'react'
import React from 'react'
import Badge, { BadgeState } from '@/app/components/base/badge/index'
import type { VersionProps } from '../../types'
type Props = {
hasInstalled: boolean
installedVersion?: string
toInstallVersion: string
}
const Version: FC<Props> = ({
const Version: FC<VersionProps> = ({
hasInstalled,
installedVersion,
toInstallVersion,

View File

@ -1,6 +1,7 @@
import { useCheckInstalled as useDoCheckInstalled } from '@/service/use-plugins'
import { useMemo } from 'react'
import type { VersionInfo } from '../../types'
type Props = {
pluginIds: string[],
enabled: boolean
@ -12,10 +13,7 @@ const useCheckInstalled = (props: Props) => {
if (!data)
return undefined
const res: Record<string, {
installedVersion: string,
uniqueIdentifier: string
}> = {}
const res: Record<string, VersionInfo> = {}
data?.plugins.forEach((plugin) => {
res[plugin.plugin_id] = {
installedVersion: plugin.declaration.version,

View File

@ -6,11 +6,13 @@ import { pluginManifestToCardPluginProps } from '../../utils'
import { useUploadGitHub } from '@/service/use-plugins'
import Loading from '../../base/loading'
import LoadedItem from './loaded-item'
import type { VersionProps } from '@/app/components/plugins/types'
type Props = {
checked: boolean
onCheckedChange: (plugin: Plugin) => void
dependency: GitHubItemAndMarketPlaceDependency
versionInfo: VersionProps
onFetchedPayload: (payload: Plugin) => void
onFetchError: () => void
}
@ -19,6 +21,7 @@ const Item: FC<Props> = ({
checked,
onCheckedChange,
dependency,
versionInfo,
onFetchedPayload,
onFetchError,
}) => {
@ -50,6 +53,7 @@ const Item: FC<Props> = ({
return (
<LoadedItem
payload={payload}
versionInfo={versionInfo}
checked={checked}
onCheckedChange={onCheckedChange}
/>

View File

@ -4,15 +4,17 @@ import React from 'react'
import type { Plugin } from '../../../types'
import Card from '../../../card'
import Checkbox from '@/app/components/base/checkbox'
import Badge, { BadgeState } from '@/app/components/base/badge/index'
import useGetIcon from '../../base/use-get-icon'
import { MARKETPLACE_API_PREFIX } from '@/config'
import Version from '../../base/version'
import type { VersionProps } from '../../../types'
type Props = {
checked: boolean
onCheckedChange: (plugin: Plugin) => void
payload: Plugin
isFromMarketPlace?: boolean
versionInfo: VersionProps
}
const LoadedItem: FC<Props> = ({
@ -20,8 +22,13 @@ const LoadedItem: FC<Props> = ({
onCheckedChange,
payload,
isFromMarketPlace,
versionInfo: particleVersionInfo,
}) => {
const { getIconUrl } = useGetIcon()
const versionInfo = {
...particleVersionInfo,
toInstallVersion: payload.version,
}
return (
<div className='flex items-center space-x-2'>
<Checkbox
@ -35,7 +42,7 @@ const LoadedItem: FC<Props> = ({
...payload,
icon: isFromMarketPlace ? `${MARKETPLACE_API_PREFIX}/plugins/${payload.org}/${payload.name}/icon` : getIconUrl(payload.icon),
}}
titleLeft={payload.version ? <Badge className='mx-1' size="s" state={BadgeState.Default}>{payload.version}</Badge> : null}
titleLeft={payload.version ? <Version {...versionInfo} /> : null}
/>
</div>
)

View File

@ -4,25 +4,31 @@ import React from 'react'
import type { Plugin } from '../../../types'
import Loading from '../../base/loading'
import LoadedItem from './loaded-item'
import type { VersionProps } from '@/app/components/plugins/types'
type Props = {
checked: boolean
onCheckedChange: (plugin: Plugin) => void
payload?: Plugin
version: string
versionInfo: VersionProps
}
const MarketPlaceItem: FC<Props> = ({
checked,
onCheckedChange,
payload,
version,
versionInfo,
}) => {
if (!payload) return <Loading />
return (
<LoadedItem
checked={checked}
onCheckedChange={onCheckedChange}
payload={payload}
payload={{ ...payload, version }}
isFromMarketPlace
versionInfo={versionInfo}
/>
)
}

View File

@ -6,12 +6,14 @@ import type { PackageDependency } from '../../../types'
import { pluginManifestToCardPluginProps } from '../../utils'
import LoadedItem from './loaded-item'
import LoadingError from '../../base/loading-error'
import type { VersionProps } from '@/app/components/plugins/types'
type Props = {
checked: boolean
onCheckedChange: (plugin: Plugin) => void
payload: PackageDependency
isFromMarketPlace?: boolean
versionInfo: VersionProps
}
const PackageItem: FC<Props> = ({
@ -19,6 +21,7 @@ const PackageItem: FC<Props> = ({
checked,
onCheckedChange,
isFromMarketPlace,
versionInfo,
}) => {
if (!payload.value?.manifest)
return <LoadingError />
@ -30,6 +33,7 @@ const PackageItem: FC<Props> = ({
checked={checked}
onCheckedChange={onCheckedChange}
isFromMarketPlace={isFromMarketPlace}
versionInfo={versionInfo}
/>
)
}

View File

@ -1,10 +1,11 @@
'use client'
import type { FC } from 'react'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import type { Dependency, GitHubItemAndMarketPlaceDependency, PackageDependency, Plugin } from '../../../types'
import type { Dependency, GitHubItemAndMarketPlaceDependency, PackageDependency, Plugin, VersionInfo } from '../../../types'
import MarketplaceItem from '../item/marketplace-item'
import GithubItem from '../item/github-item'
import { useFetchPluginsInMarketPlaceByIds, useFetchPluginsInMarketPlaceByInfo } from '@/service/use-plugins'
import useCheckInstalled from '@/app/components/plugins/install-plugin/hooks/use-check-installed'
import produce from 'immer'
import PackageItem from '../item/package-item'
import LoadingError from '../../base/loading-error'
@ -13,7 +14,7 @@ type Props = {
allPlugins: Dependency[]
selectedPlugins: Plugin[]
onSelect: (plugin: Plugin, selectedIndex: number) => void
onLoadedAllPlugin: () => void
onLoadedAllPlugin: (installedInfo: Record<string, VersionInfo>) => void
isFromMarketPlace?: boolean
}
@ -28,6 +29,7 @@ const InstallByDSLList: FC<Props> = ({
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)
@ -45,6 +47,7 @@ const InstallByDSLList: FC<Props> = ({
})
return _plugins
})())
const pluginsRef = React.useRef<(Plugin | undefined)[]>(plugins)
const setPlugins = useCallback((p: (Plugin | undefined)[]) => {
@ -132,11 +135,30 @@ const InstallByDSLList: FC<Props> = ({
}, [infoByMetaError, infoByIdError])
const isLoadedAllData = (plugins.filter(p => !!p).length + errorIndexes.length) === allPlugins.length
const { installedInfo, isLoading: isLoadingCheckInstalled } = useCheckInstalled({
pluginIds: plugins?.filter(p => !!p).map((d) => {
return `${d?.org}/${d?.name}`
}) || [],
enabled: isLoadedAllData,
})
const getVersionInfo = useCallback((pluginId: string) => {
const pluginDetail = installedInfo?.[pluginId]
const hasInstalled = !!pluginDetail
return {
hasInstalled,
installedVersion: pluginDetail?.installedVersion,
toInstallVersion: '',
}
}, [installedInfo])
useEffect(() => {
if (isLoadedAllData)
onLoadedAllPlugin()
if (isLoadedAllData && installedInfo)
onLoadedAllPlugin(installedInfo!)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoadedAllData])
}, [isLoadedAllData, installedInfo])
const handleSelect = useCallback((index: number) => {
return () => {
@ -151,6 +173,7 @@ const InstallByDSLList: FC<Props> = ({
<LoadingError key={index} />
)
}
const plugin = plugins[index]
if (d.type === 'github') {
return (<GithubItem
key={index}
@ -159,6 +182,7 @@ const InstallByDSLList: FC<Props> = ({
dependency={d as GitHubItemAndMarketPlaceDependency}
onFetchedPayload={handleGitHubPluginFetched(index)}
onFetchError={handleGitHubPluginFetchError(index)}
versionInfo={getVersionInfo(`${plugin?.org}/${plugin?.name}`)}
/>)
}
@ -169,6 +193,8 @@ const InstallByDSLList: FC<Props> = ({
checked={!!selectedPlugins.find(p => p.plugin_id === plugins[index]?.plugin_id)}
onCheckedChange={handleSelect(index)}
payload={plugins[index] as Plugin}
version={(d as GitHubItemAndMarketPlaceDependency).value.version!}
versionInfo={getVersionInfo(`${plugin?.org}/${plugin?.name}`)}
/>
)
}
@ -181,6 +207,7 @@ const InstallByDSLList: FC<Props> = ({
onCheckedChange={handleSelect(index)}
payload={d as PackageDependency}
isFromMarketPlace={isFromMarketPlace}
versionInfo={getVersionInfo(`${plugin?.org}/${plugin?.name}`)}
/>
)
})

View File

@ -1,12 +1,12 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import type { Dependency, InstallStatusResponse, Plugin } from '../../../types'
import React, { useCallback, useState } from 'react'
import type { Dependency, InstallStatusResponse, Plugin, VersionInfo } from '../../../types'
import Button from '@/app/components/base/button'
import { RiLoader2Line } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import InstallMulti from './install-multi'
import { useInstallFromMarketplaceAndGitHub } from '@/service/use-plugins'
import { useInstallOrUpdate } from '@/service/use-plugins'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
const i18nPrefix = 'plugin.installModal'
@ -43,12 +43,15 @@ const Install: FC<Props> = ({
}
const [canInstall, setCanInstall] = React.useState(false)
const handleLoadedAllPlugin = useCallback(() => {
const [installedInfo, setInstalledInfo] = useState<Record<string, VersionInfo> | undefined>(undefined)
const handleLoadedAllPlugin = useCallback((installedInfo: Record<string, VersionInfo> | undefined) => {
setInstalledInfo(installedInfo)
setCanInstall(true)
}, [])
// Install from marketplace and github
const { mutate: installFromMarketplaceAndGitHub, isPending: isInstalling } = useInstallFromMarketplaceAndGitHub({
const { mutate: installOrUpdate, isPending: isInstalling } = useInstallOrUpdate({
onSuccess: (res: InstallStatusResponse[]) => {
onInstalled(selectedPlugins, res.map((r, i) => {
return ({
@ -62,9 +65,10 @@ const Install: FC<Props> = ({
},
})
const handleInstall = () => {
installFromMarketplaceAndGitHub({
installOrUpdate({
payload: allPlugins.filter((_d, index) => selectedIndexes.includes(index)),
plugin: selectedPlugins,
installedInfo: installedInfo!,
})
}
return (

View File

@ -359,3 +359,14 @@ export type Version = {
export type VersionListResponse = {
versions: Version[]
}
export type VersionInfo = {
installedVersion: string,
uniqueIdentifier: string
}
export type VersionProps = {
hasInstalled: boolean
installedVersion?: string
toInstallVersion: string
}

View File

@ -12,6 +12,7 @@ import type {
PluginTask,
PluginsFromMarketplaceByInfoResponse,
PluginsFromMarketplaceResponse,
VersionInfo,
VersionListResponse,
uploadGitHubResponse,
} from '@/app/components/plugins/types'
@ -145,22 +146,30 @@ export const useUploadGitHub = (payload: {
})
}
export const useInstallFromMarketplaceAndGitHub = ({
export const useInstallOrUpdate = ({
onSuccess,
}: {
onSuccess?: (res: { success: boolean }[]) => void
}) => {
const { mutateAsync: updatePackageFromMarketPlace } = useUpdatePackageFromMarketPlace()
return useMutation({
mutationFn: (data: {
payload: Dependency[],
plugin: Plugin[],
installedInfo: Record<string, VersionInfo>
}) => {
const { payload, plugin } = data
const { payload, plugin, installedInfo } = data
return Promise.all(payload.map(async (item, i) => {
try {
const orgAndName = `${plugin[i]?.org}/${plugin[i]?.name}`
const installedPayload = installedInfo[orgAndName]
const isInstalled = !!installedPayload
let uniqueIdentifier = ''
if (item.type === 'github') {
const data = item as GitHubItemAndMarketPlaceDependency
let pluginId = ''
// From local bundle don't have data.value.github_plugin_unique_identifier
if (!data.value.github_plugin_unique_identifier) {
const { unique_identifier } = await post<uploadGitHubResponse>('/workspaces/current/plugin/upload/github', {
@ -170,32 +179,61 @@ export const useInstallFromMarketplaceAndGitHub = ({
package: data.value.packages! || data.value.package!,
},
})
pluginId = unique_identifier
uniqueIdentifier = data.value.github_plugin_unique_identifier! || unique_identifier
// has the same version, but not installed
if (uniqueIdentifier === installedPayload?.uniqueIdentifier) {
return {
success: true,
}
}
}
if (!isInstalled) {
await post<InstallPackageResponse>('/workspaces/current/plugin/install/github', {
body: {
repo: data.value.repo!,
version: data.value.release! || data.value.version!,
package: data.value.packages! || data.value.package!,
plugin_unique_identifier: uniqueIdentifier,
},
})
}
await post<InstallPackageResponse>('/workspaces/current/plugin/install/github', {
body: {
repo: data.value.repo!,
version: data.value.release! || data.value.version!,
package: data.value.packages! || data.value.package!,
plugin_unique_identifier: data.value.github_plugin_unique_identifier! || pluginId,
},
})
}
if (item.type === 'marketplace') {
const data = item as GitHubItemAndMarketPlaceDependency
await post<InstallPackageResponse>('/workspaces/current/plugin/install/marketplace', {
body: {
plugin_unique_identifiers: [data.value.plugin_unique_identifier! || plugin[i]?.plugin_id],
},
})
uniqueIdentifier = data.value.plugin_unique_identifier! || plugin[i]?.plugin_id
if (uniqueIdentifier === installedPayload?.uniqueIdentifier) {
return {
success: true,
}
}
if (!isInstalled) {
await post<InstallPackageResponse>('/workspaces/current/plugin/install/marketplace', {
body: {
plugin_unique_identifiers: [uniqueIdentifier],
},
})
}
}
if (item.type === 'package') {
const data = item as PackageDependency
await post<InstallPackageResponse>('/workspaces/current/plugin/install/pkg', {
body: {
plugin_unique_identifiers: [data.value.unique_identifier],
},
uniqueIdentifier = data.value.unique_identifier
if (uniqueIdentifier === installedPayload?.uniqueIdentifier) {
return {
success: true,
}
}
if (!isInstalled) {
await post<InstallPackageResponse>('/workspaces/current/plugin/install/pkg', {
body: {
plugin_unique_identifiers: [uniqueIdentifier],
},
})
}
}
if (isInstalled) {
await updatePackageFromMarketPlace({
original_plugin_unique_identifier: installedPayload?.uniqueIdentifier,
new_plugin_unique_identifier: uniqueIdentifier,
})
}
return ({ success: true })