feat: handle from market install
This commit is contained in:
parent
0886d7bb8b
commit
0dcbb34cab
@ -41,7 +41,7 @@ const Card = ({
|
|||||||
const { type, name, org, label, brief, icon, verified } = payload
|
const { type, name, org, label, brief, icon, verified } = payload
|
||||||
|
|
||||||
const getLocalizedText = (obj: Record<string, string> | undefined) =>
|
const getLocalizedText = (obj: Record<string, string> | undefined) =>
|
||||||
obj?.[locale] || obj?.['en-US'] || ''
|
obj?.[locale] || obj?.['en-US'] || obj?.en_US || ''
|
||||||
|
|
||||||
const wrapClassName = cn('relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)
|
const wrapClassName = cn('relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { PluginDeclaration } from '../../types'
|
import type { PluginDeclaration, PluginManifestInMarket } from '../../types'
|
||||||
import Card from '../../card'
|
import Card from '../../card'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import { pluginManifestToCardPluginProps } from '../utils'
|
import { pluginManifestInMarketToPluginProps, pluginManifestToCardPluginProps } from '../utils'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Badge, { BadgeState } from '@/app/components/base/badge/index'
|
import Badge, { BadgeState } from '@/app/components/base/badge/index'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
payload?: PluginDeclaration | null
|
payload?: PluginDeclaration | PluginManifestInMarket | null
|
||||||
|
isMarketPayload?: boolean
|
||||||
isFailed: boolean
|
isFailed: boolean
|
||||||
errMsg?: string | null
|
errMsg?: string | null
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
@ -17,6 +18,7 @@ type Props = {
|
|||||||
|
|
||||||
const Installed: FC<Props> = ({
|
const Installed: FC<Props> = ({
|
||||||
payload,
|
payload,
|
||||||
|
isMarketPayload,
|
||||||
isFailed,
|
isFailed,
|
||||||
errMsg,
|
errMsg,
|
||||||
onCancel,
|
onCancel,
|
||||||
@ -30,10 +32,10 @@ const Installed: FC<Props> = ({
|
|||||||
<div className='flex p-2 items-start content-start gap-1 self-stretch flex-wrap rounded-2xl bg-background-section-burn'>
|
<div className='flex p-2 items-start content-start gap-1 self-stretch flex-wrap rounded-2xl bg-background-section-burn'>
|
||||||
<Card
|
<Card
|
||||||
className='w-full'
|
className='w-full'
|
||||||
payload={pluginManifestToCardPluginProps(payload)}
|
payload={isMarketPayload ? pluginManifestInMarketToPluginProps(payload as PluginManifestInMarket) : pluginManifestToCardPluginProps(payload as PluginDeclaration)}
|
||||||
installed={!isFailed}
|
installed={!isFailed}
|
||||||
installFailed={isFailed}
|
installFailed={isFailed}
|
||||||
titleLeft={<Badge className='mx-1' size="s" state={BadgeState.Default}>{payload.version}</Badge>}
|
titleLeft={<Badge className='mx-1' size="s" state={BadgeState.Default}>{(payload as PluginDeclaration).version || (payload as PluginManifestInMarket).latest_version}</Badge>}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import React, { useCallback, useState } from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import Modal from '@/app/components/base/modal'
|
import Modal from '@/app/components/base/modal'
|
||||||
import type { PluginDeclaration } from '../../types'
|
import type { PluginManifestInMarket } from '../../types'
|
||||||
import { InstallStep } from '../../types'
|
import { InstallStep } from '../../types'
|
||||||
import Install from './steps/install'
|
import Install from './steps/install'
|
||||||
import Installed from '../base/installed'
|
import Installed from '../base/installed'
|
||||||
@ -10,9 +10,9 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
const i18nPrefix = 'plugin.installModal'
|
const i18nPrefix = 'plugin.installModal'
|
||||||
|
|
||||||
interface InstallFromMarketplaceProps {
|
type InstallFromMarketplaceProps = {
|
||||||
uniqueIdentifier: string
|
uniqueIdentifier: string
|
||||||
manifest: PluginDeclaration
|
manifest: PluginManifestInMarket
|
||||||
onSuccess: () => void
|
onSuccess: () => void
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
@ -75,6 +75,7 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
|
|||||||
([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
|
([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
|
||||||
<Installed
|
<Installed
|
||||||
payload={manifest!}
|
payload={manifest!}
|
||||||
|
isMarketPayload
|
||||||
isFailed={step === InstallStep.installFailed}
|
isFailed={step === InstallStep.installFailed}
|
||||||
errMsg={errorMsg}
|
errMsg={errorMsg}
|
||||||
onCancel={onSuccess}
|
onCancel={onSuccess}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { RiInformation2Line } from '@remixicon/react'
|
import { RiInformation2Line } from '@remixicon/react'
|
||||||
import type { PluginDeclaration } from '../../../types'
|
import type { PluginManifestInMarket } from '../../../types'
|
||||||
import Card from '../../../card'
|
import Card from '../../../card'
|
||||||
import { pluginManifestToCardPluginProps } from '../../utils'
|
import { pluginManifestInMarketToPluginProps } from '../../utils'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RiLoader2Line } from '@remixicon/react'
|
import { RiLoader2Line } from '@remixicon/react'
|
||||||
@ -14,9 +14,9 @@ import checkTaskStatus from '../../base/check-task-status'
|
|||||||
|
|
||||||
const i18nPrefix = 'plugin.installModal'
|
const i18nPrefix = 'plugin.installModal'
|
||||||
|
|
||||||
interface Props {
|
type Props = {
|
||||||
uniqueIdentifier: string
|
uniqueIdentifier: string
|
||||||
payload: PluginDeclaration
|
payload: PluginManifestInMarket
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
onInstalled: () => void
|
onInstalled: () => void
|
||||||
onFailed: (message?: string) => void
|
onFailed: (message?: string) => void
|
||||||
@ -74,14 +74,14 @@ const Installed: FC<Props> = ({
|
|||||||
|
|
||||||
const versionInfo = useMemo(() => {
|
const versionInfo = useMemo(() => {
|
||||||
return (<>{
|
return (<>{
|
||||||
payload.version === toInstallVersion || !supportCheckInstalled
|
payload.latest_version === toInstallVersion || !supportCheckInstalled
|
||||||
? (
|
? (
|
||||||
<Badge className='mx-1' size="s" state={BadgeState.Default}>{payload.version}</Badge>
|
<Badge className='mx-1' size="s" state={BadgeState.Default}>{payload.latest_version}</Badge>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<>
|
<>
|
||||||
<Badge className='mx-1' size="s" state={BadgeState.Warning}>
|
<Badge className='mx-1' size="s" state={BadgeState.Warning}>
|
||||||
{`${payload.version} -> ${toInstallVersion}`}
|
{`${payload.latest_version} -> ${toInstallVersion}`}
|
||||||
</Badge>
|
</Badge>
|
||||||
<div className='flex px-0.5 justify-center items-center gap-0.5'>
|
<div className='flex px-0.5 justify-center items-center gap-0.5'>
|
||||||
<div className='text-text-warning system-xs-medium'>Used in 3 apps</div>
|
<div className='text-text-warning system-xs-medium'>Used in 3 apps</div>
|
||||||
@ -101,7 +101,7 @@ const Installed: FC<Props> = ({
|
|||||||
<div className='flex p-2 items-start content-start gap-1 self-stretch flex-wrap rounded-2xl bg-background-section-burn'>
|
<div className='flex p-2 items-start content-start gap-1 self-stretch flex-wrap rounded-2xl bg-background-section-burn'>
|
||||||
<Card
|
<Card
|
||||||
className='w-full'
|
className='w-full'
|
||||||
payload={pluginManifestToCardPluginProps(payload)}
|
payload={pluginManifestInMarketToPluginProps(payload)}
|
||||||
titleLeft={versionInfo}
|
titleLeft={versionInfo}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Plugin, PluginDeclaration } from '../types'
|
import type { Plugin, PluginDeclaration, PluginManifestInMarket } from '../types'
|
||||||
|
|
||||||
export const pluginManifestToCardPluginProps = (pluginManifest: PluginDeclaration): Plugin => {
|
export const pluginManifestToCardPluginProps = (pluginManifest: PluginDeclaration): Plugin => {
|
||||||
return {
|
return {
|
||||||
@ -20,3 +20,24 @@ export const pluginManifestToCardPluginProps = (pluginManifest: PluginDeclaratio
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const pluginManifestInMarketToPluginProps = (pluginManifest: PluginManifestInMarket): Plugin => {
|
||||||
|
return {
|
||||||
|
type: pluginManifest.category,
|
||||||
|
category: pluginManifest.category,
|
||||||
|
name: pluginManifest.name,
|
||||||
|
version: pluginManifest.latest_version,
|
||||||
|
latest_version: pluginManifest.latest_version,
|
||||||
|
org: pluginManifest.org,
|
||||||
|
label: pluginManifest.label,
|
||||||
|
brief: pluginManifest.brief,
|
||||||
|
icon: pluginManifest.icon,
|
||||||
|
verified: pluginManifest.verified,
|
||||||
|
introduction: pluginManifest.introduction,
|
||||||
|
repository: '',
|
||||||
|
install_count: 0,
|
||||||
|
endpoint: {
|
||||||
|
settings: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,9 +29,10 @@ import {
|
|||||||
useRouter,
|
useRouter,
|
||||||
useSearchParams,
|
useSearchParams,
|
||||||
} from 'next/navigation'
|
} from 'next/navigation'
|
||||||
import type { PluginDeclaration } from '../types'
|
import type { PluginDeclaration, PluginManifestInMarket } from '../types'
|
||||||
import { sleep } from '@/utils'
|
import { sleep } from '@/utils'
|
||||||
import { fetchManifestFromMarketPlace } from '@/service/plugins'
|
import { fetchManifestFromMarketPlace } from '@/service/plugins'
|
||||||
|
import { marketplaceApiPrefix } from '@/config'
|
||||||
|
|
||||||
const PACKAGE_IDS_KEY = 'package-ids'
|
const PACKAGE_IDS_KEY = 'package-ids'
|
||||||
|
|
||||||
@ -68,14 +69,18 @@ const PluginPage = ({
|
|||||||
url.searchParams.delete(PACKAGE_IDS_KEY)
|
url.searchParams.delete(PACKAGE_IDS_KEY)
|
||||||
replace(url.toString())
|
replace(url.toString())
|
||||||
}
|
}
|
||||||
const [manifest, setManifest] = useState<PluginDeclaration | null>(null)
|
const [manifest, setManifest] = useState<PluginDeclaration | PluginManifestInMarket | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
await sleep(100)
|
await sleep(100)
|
||||||
if (packageId) {
|
if (packageId) {
|
||||||
const { data } = await fetchManifestFromMarketPlace(encodeURIComponent(packageId))
|
const { data } = await fetchManifestFromMarketPlace(encodeURIComponent(packageId))
|
||||||
setManifest(data.plugin)
|
const { plugin } = data
|
||||||
|
setManifest({
|
||||||
|
...plugin,
|
||||||
|
icon: `${marketplaceApiPrefix}/plugins/${plugin.org}/${plugin.name}/icon`,
|
||||||
|
})
|
||||||
showInstallFromMarketplace()
|
showInstallFromMarketplace()
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
@ -229,7 +234,7 @@ const PluginPage = ({
|
|||||||
{
|
{
|
||||||
isShowInstallFromMarketplace && (
|
isShowInstallFromMarketplace && (
|
||||||
<InstallFromMarketplace
|
<InstallFromMarketplace
|
||||||
manifest={manifest!}
|
manifest={manifest! as PluginManifestInMarket}
|
||||||
uniqueIdentifier={packageId}
|
uniqueIdentifier={packageId}
|
||||||
onClose={hideInstallFromMarketplace}
|
onClose={hideInstallFromMarketplace}
|
||||||
onSuccess={hideInstallFromMarketplace}
|
onSuccess={hideInstallFromMarketplace}
|
||||||
|
@ -70,6 +70,18 @@ export type PluginDeclaration = {
|
|||||||
model: any // TODO
|
model: any // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PluginManifestInMarket = {
|
||||||
|
name: string
|
||||||
|
org: string
|
||||||
|
icon: string
|
||||||
|
label: Record<Locale, string>
|
||||||
|
category: PluginType
|
||||||
|
latest_version: string
|
||||||
|
brief: Record<Locale, string>
|
||||||
|
introduction: string
|
||||||
|
verified: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type PluginDetail = {
|
export type PluginDetail = {
|
||||||
id: string
|
id: string
|
||||||
created_at: string
|
created_at: string
|
||||||
|
@ -7,6 +7,7 @@ import type {
|
|||||||
EndpointsResponse,
|
EndpointsResponse,
|
||||||
InstallPackageResponse,
|
InstallPackageResponse,
|
||||||
PluginDeclaration,
|
PluginDeclaration,
|
||||||
|
PluginManifestInMarket,
|
||||||
TaskStatusResponse,
|
TaskStatusResponse,
|
||||||
UpdateEndpointRequest,
|
UpdateEndpointRequest,
|
||||||
} from '@/app/components/plugins/types'
|
} from '@/app/components/plugins/types'
|
||||||
@ -80,7 +81,7 @@ export const fetchManifest = async (uniqueIdentifier: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) => {
|
export const fetchManifestFromMarketPlace = async (uniqueIdentifier: string) => {
|
||||||
return getMarketplace<{ data: { plugin: PluginDeclaration } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`)
|
return getMarketplace<{ data: { plugin: PluginManifestInMarket } }>(`/plugins/identifier?unique_identifier=${uniqueIdentifier}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const installPackageFromMarketPlace = async (uniqueIdentifier: string) => {
|
export const installPackageFromMarketPlace = async (uniqueIdentifier: string) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user