feat: support install failed

This commit is contained in:
Joel 2024-10-23 17:52:39 +08:00
parent 474cedf653
commit d357f359ab
11 changed files with 64 additions and 19 deletions

View File

@ -1,4 +1,4 @@
import { RiCheckLine } from '@remixicon/react' import { RiCheckLine, RiCloseLine } from '@remixicon/react'
import AppIcon from '@/app/components/base/app-icon' import AppIcon from '@/app/components/base/app-icon'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
@ -6,14 +6,17 @@ const Icon = ({
className, className,
src, src,
installed = false, installed = false,
installFailed = false,
}: { }: {
className?: string className?: string
src: string | { src: string | {
'content': string content: string
'background': string background: string
} }
installed?: boolean installed?: boolean
installFailed?: boolean
}) => { }) => {
const iconClassName = 'flex justify-center items-center gap-2 absolute bottom-[-4px] right-[-4px] w-[18px] h-[18px] rounded-full border-2 border-components-panel-bg'
if (typeof src === 'object') { if (typeof src === 'object') {
return ( return (
<div className={cn('relative', className)}> <div className={cn('relative', className)}>
@ -34,11 +37,18 @@ const Icon = ({
backgroundImage: `url(${src})`, backgroundImage: `url(${src})`,
}} }}
> >
{installed {
&& <div className='flex justify-center items-center gap-2 absolute bottom-[-4px] right-[-4px] w-[18px] h-[18px] rounded-full border-2 border-components-panel-bg bg-state-success-solid'> installed
&& <div className={cn(iconClassName, 'bg-state-success-solid')}>
<RiCheckLine className='w-3 h-3 text-text-primary-on-surface' /> <RiCheckLine className='w-3 h-3 text-text-primary-on-surface' />
</div> </div>
} }
{
installFailed
&& <div className={cn(iconClassName, 'bg-state-destructive-solid')}>
<RiCloseLine className='w-3 h-3 text-text-primary-on-surface' />
</div>
}
</div> </div>
) )
} }

View File

@ -16,6 +16,7 @@ export type Props = {
payload: Plugin payload: Plugin
titleLeft?: React.ReactNode titleLeft?: React.ReactNode
installed?: boolean installed?: boolean
installFailed?: boolean
hideCornerMark?: boolean hideCornerMark?: boolean
descriptionLineRows?: number descriptionLineRows?: number
footer?: React.ReactNode footer?: React.ReactNode
@ -28,6 +29,7 @@ const Card = ({
payload, payload,
titleLeft, titleLeft,
installed, installed,
installFailed,
hideCornerMark, hideCornerMark,
descriptionLineRows = 2, descriptionLineRows = 2,
footer, footer,
@ -56,7 +58,7 @@ const Card = ({
{!hideCornerMark && <CornerMark text={type} />} {!hideCornerMark && <CornerMark text={type} />}
{/* Header */} {/* Header */}
<div className="flex"> <div className="flex">
<Icon src={icon} installed={installed} /> <Icon src={icon} installed={installed} installFailed={installFailed} />
<div className="ml-3 grow"> <div className="ml-3 grow">
<div className="flex items-center h-5"> <div className="flex items-center h-5">
<Title title={getLocalizedText(label)} /> <Title title={getLocalizedText(label)} />

View File

@ -23,7 +23,7 @@ const InstallFromLocalPackage: React.FC<InstallFromLocalPackageProps> = ({
onClose, onClose,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
// uploading -> readyToInstall -> installed // uploading -> readyToInstall -> installed/failed
const [step, setStep] = useState<InstallStep>(InstallStep.uploading) const [step, setStep] = useState<InstallStep>(InstallStep.uploading)
const [uniqueIdentifier, setUniqueIdentifier] = useState<string | null>(null) const [uniqueIdentifier, setUniqueIdentifier] = useState<string | null>(null)
@ -31,6 +31,8 @@ const InstallFromLocalPackage: React.FC<InstallFromLocalPackageProps> = ({
const getTitle = useCallback(() => { const getTitle = useCallback(() => {
if (step === InstallStep.installed) if (step === InstallStep.installed)
return t(`${i18nPrefix}.installedSuccessfully`) return t(`${i18nPrefix}.installedSuccessfully`)
if (step === InstallStep.installFailed)
return t(`${i18nPrefix}.installFailed`)
return t(`${i18nPrefix}.installPlugin`) return t(`${i18nPrefix}.installPlugin`)
}, []) }, [])
const [manifest, setManifest] = useState<PluginDeclaration | null>(toolNotionManifest) const [manifest, setManifest] = useState<PluginDeclaration | null>(toolNotionManifest)
@ -48,6 +50,10 @@ const InstallFromLocalPackage: React.FC<InstallFromLocalPackageProps> = ({
setStep(InstallStep.installed) setStep(InstallStep.installed)
}, []) }, [])
const handleFailed = useCallback(() => {
setStep(InstallStep.installFailed)
}, [])
return ( return (
<Modal <Modal
isShow={true} isShow={true}
@ -73,13 +79,15 @@ const InstallFromLocalPackage: React.FC<InstallFromLocalPackageProps> = ({
payload={manifest!} payload={manifest!}
onCancel={onClose} onCancel={onClose}
onInstalled={handleInstalled} onInstalled={handleInstalled}
onFailed={handleFailed}
/> />
) )
} }
{ {
step === InstallStep.installed && ( ([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
<Installed <Installed
payload={manifest!} payload={manifest!}
isFailed={step === InstallStep.installFailed}
onCancel={onClose} onCancel={onClose}
/> />
) )

View File

@ -15,12 +15,14 @@ type Props = {
payload: PluginDeclaration payload: PluginDeclaration
onCancel: () => void onCancel: () => void
onInstalled: () => void onInstalled: () => void
onFailed: () => void
} }
const Installed: FC<Props> = ({ const Installed: FC<Props> = ({
payload, payload,
onCancel, onCancel,
onInstalled, onInstalled,
onFailed,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isInstalling, setIsInstalling] = React.useState(false) const [isInstalling, setIsInstalling] = React.useState(false)
@ -29,7 +31,8 @@ const Installed: FC<Props> = ({
if (isInstalling) return if (isInstalling) return
setIsInstalling(true) setIsInstalling(true)
await sleep(1500) await sleep(1500)
onInstalled() // onInstalled()
onFailed()
} }
return ( return (

View File

@ -9,24 +9,26 @@ import { useTranslation } from 'react-i18next'
type Props = { type Props = {
payload: PluginDeclaration payload: PluginDeclaration
isFailed: boolean
onCancel: () => void onCancel: () => void
} }
const Installed: FC<Props> = ({ const Installed: FC<Props> = ({
payload, payload,
isFailed,
onCancel, onCancel,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<> <>
<div className='flex flex-col px-6 py-3 justify-center items-start gap-4 self-stretch'> <div className='flex flex-col px-6 py-3 justify-center items-start gap-4 self-stretch'>
<p className='text-text-secondary system-md-regular'>The plugin has been installed successfully.</p> <p className='text-text-secondary system-md-regular'>{t(`plugin.installModal.${isFailed ? 'installFailedDesc' : 'installedSuccessfullyDesc'}`)}</p>
<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={pluginManifestToCardPluginProps(payload)}
installed installed={!isFailed}
installFailed={isFailed}
/> />
</div> </div>
</div> </div>

View File

@ -24,7 +24,7 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
onClose, onClose,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
// readyToInstall -> check installed -> installed // readyToInstall -> check installed -> installed/failed
const [step, setStep] = useState<InstallStep>(InstallStep.readyToInstall) const [step, setStep] = useState<InstallStep>(InstallStep.readyToInstall)
// TODO: check installed in beta version. // TODO: check installed in beta version.
@ -32,13 +32,19 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
const getTitle = useCallback(() => { const getTitle = useCallback(() => {
if (step === InstallStep.installed) if (step === InstallStep.installed)
return t(`${i18nPrefix}.installedSuccessfully`) return t(`${i18nPrefix}.installedSuccessfully`)
if (step === InstallStep.installFailed)
return t(`${i18nPrefix}.installFailed`)
return t(`${i18nPrefix}.installPlugin`) return t(`${i18nPrefix}.installPlugin`)
}, []) }, [])
const handleInstalled = useCallback(async () => { const handleInstalled = useCallback(() => {
setStep(InstallStep.installed) setStep(InstallStep.installed)
}, []) }, [])
const handleFailed = useCallback(() => {
setStep(InstallStep.installFailed)
}, [])
return ( return (
<Modal <Modal
isShow={true} isShow={true}
@ -57,13 +63,15 @@ const InstallFromMarketplace: React.FC<InstallFromMarketplaceProps> = ({
payload={manifest!} payload={manifest!}
onCancel={onClose} onCancel={onClose}
onInstalled={handleInstalled} onInstalled={handleInstalled}
onFailed={handleFailed}
/> />
) )
} }
{ {
step === InstallStep.installed && ( ([InstallStep.installed, InstallStep.installFailed].includes(step)) && (
<Installed <Installed
payload={manifest!} payload={manifest!}
isFailed={step === InstallStep.installFailed}
onCancel={onSuccess} onCancel={onSuccess}
/> />
) )

View File

@ -17,12 +17,14 @@ type Props = {
payload: PluginDeclaration payload: PluginDeclaration
onCancel: () => void onCancel: () => void
onInstalled: () => void onInstalled: () => void
onFailed: () => void
} }
const Installed: FC<Props> = ({ const Installed: FC<Props> = ({
payload, payload,
onCancel, onCancel,
onInstalled, onInstalled,
onFailed,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [isInstalling, setIsInstalling] = React.useState(false) const [isInstalling, setIsInstalling] = React.useState(false)
@ -32,6 +34,7 @@ const Installed: FC<Props> = ({
setIsInstalling(true) setIsInstalling(true)
await sleep(1500) await sleep(1500)
onInstalled() onInstalled()
// onFailed()
} }
const toInstallVersion = '1.3.0' const toInstallVersion = '1.3.0'

View File

@ -9,24 +9,26 @@ import { useTranslation } from 'react-i18next'
type Props = { type Props = {
payload: PluginDeclaration payload: PluginDeclaration
isFailed: boolean
onCancel: () => void onCancel: () => void
} }
const Installed: FC<Props> = ({ const Installed: FC<Props> = ({
payload, payload,
isFailed,
onCancel, onCancel,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<> <>
<div className='flex flex-col px-6 py-3 justify-center items-start gap-4 self-stretch'> <div className='flex flex-col px-6 py-3 justify-center items-start gap-4 self-stretch'>
<p className='text-text-secondary system-md-regular'>The plugin has been installed successfully.</p> <p className='text-text-secondary system-md-regular'>{t(`plugin.installModal.${isFailed ? 'installFailedDesc' : 'installedSuccessfullyDesc'}`)}</p>
<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={pluginManifestToCardPluginProps(payload)}
installed installed={!isFailed}
installFailed={isFailed}
/> />
</div> </div>
</div> </div>

View File

@ -171,6 +171,7 @@ export enum InstallStep {
readyToInstall = 'readyToInstall', readyToInstall = 'readyToInstall',
installing = 'installing', installing = 'installing',
installed = 'installed', installed = 'installed',
installFailed = 'failed',
} }
export type GitHubAsset = { export type GitHubAsset = {

View File

@ -61,7 +61,10 @@ const translation = {
}, },
installModal: { installModal: {
installPlugin: 'Install Plugin', installPlugin: 'Install Plugin',
installedSuccessfully: 'Install successful', installedSuccessfully: 'Installation successful',
installedSuccessfullyDesc: 'The plugin has been installed successfully.',
installFailed: 'Installation failed',
installFailedDesc: 'The plugin has been installed failed.',
install: 'Install', install: 'Install',
installing: 'Installing...', installing: 'Installing...',
uploadingPackage: 'Uploading {{packageName}}...', uploadingPackage: 'Uploading {{packageName}}...',

View File

@ -62,6 +62,9 @@ const translation = {
installModal: { installModal: {
installPlugin: '安装插件', installPlugin: '安装插件',
installedSuccessfully: '安装成功', installedSuccessfully: '安装成功',
installedSuccessfullyDesc: '插件已成功安装。',
installFailed: '安装失败',
installFailedDesc: '插件安装失败。',
install: '安装', install: '安装',
installing: '安装中...', installing: '安装中...',
uploadingPackage: '上传 {{packageName}} 中...', uploadingPackage: '上传 {{packageName}} 中...',