feat: handle upgrade confirm and icon

This commit is contained in:
Joel
2026-01-29 14:57:49 +08:00
parent 255b7511ae
commit 2973968cc6
8 changed files with 152 additions and 51 deletions

View File

@ -0,0 +1,66 @@
'use client'
import type { ComponentType, FC, ReactNode, SVGProps } from 'react'
import Modal from '@/app/components/base/modal'
import styles from './style.module.css'
type Props = {
Icon?: ComponentType<SVGProps<SVGSVGElement>>
title: string
description: string
extraInfo?: ReactNode
footer?: ReactNode
show: boolean
onClose: () => void
}
const UpgradeModalBase: FC<Props> = ({
Icon,
title,
description,
extraInfo,
footer,
show,
onClose,
}) => {
return (
<Modal
isShow={show}
onClose={onClose}
closable={false}
clickOutsideNotClose
className={`${styles.surface} w-[580px] rounded-2xl !p-0`}
>
<div className="relative">
<div
aria-hidden
className={`${styles.heroOverlay} pointer-events-none absolute inset-0`}
/>
<div className="px-8 pt-8">
{Icon && (
<div className={`${styles.icon} flex size-12 items-center justify-center rounded-xl shadow-lg backdrop-blur-[5px]`}>
<Icon className="size-6 text-text-primary-on-surface" />
</div>
)}
<div className="mt-6 space-y-2">
<div className={`${styles.highlight} title-3xl-semi-bold`}>
{title}
</div>
<div className="system-md-regular text-text-tertiary">
{description}
</div>
</div>
{extraInfo}
</div>
</div>
{footer && (
<div className="mb-8 mt-10 flex justify-end space-x-2 px-8">
{footer}
</div>
)}
</Modal>
)
}
export default UpgradeModalBase

View File

@ -4,11 +4,10 @@ import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import Modal from '@/app/components/base/modal'
import UpgradeModalBase from '@/app/components/base/upgrade-modal'
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
import { useModalContext } from '@/context/modal-context'
import { SquareChecklist } from '../../base/icons/src/vender/other'
import styles from './style.module.css'
type Props = {
Icon?: React.ComponentType<React.SVGProps<SVGSVGElement>>
@ -41,50 +40,30 @@ const PlanUpgradeModal: FC<Props> = ({
}, [onClose, onUpgrade, setShowPricingModal])
return (
<Modal
isShow={show}
<UpgradeModalBase
show={show}
onClose={onClose}
closable={false}
clickOutsideNotClose
className={`${styles.surface} w-[580px] rounded-2xl !p-0`}
>
<div className="relative">
<div
aria-hidden
className={`${styles.heroOverlay} pointer-events-none absolute inset-0`}
/>
<div className="px-8 pt-8">
<div className={`${styles.icon} flex size-12 items-center justify-center rounded-xl shadow-lg backdrop-blur-[5px]`}>
<Icon className="size-6 text-text-primary-on-surface" />
</div>
<div className="mt-6 space-y-2">
<div className={`${styles.highlight} title-3xl-semi-bold`}>
{title}
</div>
<div className="system-md-regular text-text-tertiary">
{description}
</div>
</div>
{extraInfo}
</div>
</div>
<div className="mb-8 mt-10 flex justify-end space-x-2 px-8">
<Button
onClick={onClose}
>
{t('triggerLimitModal.dismiss', { ns: 'billing' })}
</Button>
<UpgradeBtn
size="custom"
isShort
onClick={handleUpgrade}
className="!h-8 !rounded-lg px-2"
labelKey="triggerLimitModal.upgrade"
loc="trigger-events-limit-modal"
/>
</div>
</Modal>
// eslint-disable-next-line ts/no-explicit-any
Icon={Icon as any}
title={title}
description={description}
extraInfo={extraInfo}
footer={(
<>
<Button onClick={onClose}>
{t('triggerLimitModal.dismiss', { ns: 'billing' })}
</Button>
<UpgradeBtn
size="custom"
isShort
onClick={handleUpgrade}
className="!h-8 !rounded-lg px-2"
labelKey="triggerLimitModal.upgrade"
loc="trigger-events-limit-modal"
/>
</>
)}
/>
)
}

View File

@ -0,0 +1,54 @@
'use client'
import type { FC } from 'react'
import { forwardRef, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import { Thinking as ThinkingIcon } from '@/app/components/base/icons/src/vender/workflow'
import UpgradeModalBase from '@/app/components/base/upgrade-modal'
const Thinking = forwardRef<SVGSVGElement, React.SVGProps<SVGSVGElement>>((props, ref) => (
// eslint-disable-next-line ts/no-explicit-any
<ThinkingIcon {...props} ref={ref as any} />
))
type Props = {
show: boolean
onClose: () => void
onUpgrade?: () => void
}
const SandboxMigrationModal: FC<Props> = ({
show,
onClose,
onUpgrade,
}) => {
const { t } = useTranslation()
const handleUpgrade = useCallback(() => {
onClose()
onUpgrade?.()
}, [onClose, onUpgrade])
return (
<UpgradeModalBase
show={show}
onClose={onClose}
Icon={Thinking}
title={t('sandboxMigrationModal.title', { ns: 'workflow' })}
description={t('sandboxMigrationModal.description', { ns: 'workflow' })}
footer={(
<>
<Button onClick={onClose}>
{t('sandboxMigrationModal.dismiss', { ns: 'workflow' })}
</Button>
<Button variant="primary" onClick={handleUpgrade}>
{t('sandboxMigrationModal.upgrade', { ns: 'workflow' })}
</Button>
</>
)}
/>
)
}
export default SandboxMigrationModal

View File

@ -13,12 +13,10 @@ import {
useRef,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import { useStore as useAppStore } from '@/app/components/app/store'
import { FeaturesProvider } from '@/app/components/base/features'
import Loading from '@/app/components/base/loading'
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
import PlanUpgradeModal from '@/app/components/billing/plan-upgrade-modal'
import WorkflowWithDefaultContext from '@/app/components/workflow'
import { useCollaboration } from '@/app/components/workflow/collaboration'
import { collaborationManager } from '@/app/components/workflow/collaboration/core/collaboration-manager'
@ -42,6 +40,7 @@ import { useAppTriggers } from '@/service/use-tools'
import { AppModeEnum } from '@/types/app'
import { useFeatures } from '../base/features/hooks'
import ViewPicker from '../workflow/view-picker'
import SandboxMigrationModal from './components/sandbox-migration-modal'
import WorkflowAppMain from './components/workflow-main'
import { useGetRunAndTraceUrl } from './hooks/use-get-run-and-trace-url'
import { useNodesSyncDraft } from './hooks/use-nodes-sync-draft'
@ -173,7 +172,6 @@ const WorkflowAppWithAdditionalContext = () => {
} = useWorkflowInit()
const workflowStore = useWorkflowStore()
const { isLoadingCurrentWorkspace, currentWorkspace } = useAppContext()
const { t } = useTranslation()
const [showMigrationModal, setShowMigrationModal] = useState(false)
const lastCheckedAppIdRef = useRef<string | null>(null)
@ -366,11 +364,9 @@ const WorkflowAppWithAdditionalContext = () => {
return (
<>
<CollaborationSession />
<PlanUpgradeModal
<SandboxMigrationModal
show={showMigrationModal}
onClose={handleCloseMigrationModal}
title={t('sandboxMigrationModal.title', { ns: 'workflow' })}
description={t('sandboxMigrationModal.description', { ns: 'workflow' })}
/>
<WorkflowWithDefaultContext
edges={edgesData}

View File

@ -1055,7 +1055,9 @@
"publishLimit.startNodeTitlePrefix": "Upgrade to",
"publishLimit.startNodeTitleSuffix": "unlock unlimited triggers per workflow",
"sandboxMigrationModal.description": "This will create a separate copy of your app, without affecting the original.",
"sandboxMigrationModal.dismiss": "Dismiss",
"sandboxMigrationModal.title": "Upgrade to filesystem-based agents",
"sandboxMigrationModal.upgrade": "Clone & Upgrade",
"sidebar.exportWarning": "Export Current Saved Version",
"sidebar.exportWarningDesc": "This will export the current saved version of your workflow. If you have unsaved changes in the editor, please save them first by using the export option in the workflow canvas.",
"singleRun.back": "Back",

View File

@ -1047,7 +1047,9 @@
"publishLimit.startNodeTitlePrefix": "升级以",
"publishLimit.startNodeTitleSuffix": "解锁每个工作流无限制的触发器",
"sandboxMigrationModal.description": "这将创建你的应用的一个独立副本,不会影响原应用。",
"sandboxMigrationModal.dismiss": "暂不升级",
"sandboxMigrationModal.title": "升级到基于文件系统的智能体",
"sandboxMigrationModal.upgrade": "复制并升级",
"sidebar.exportWarning": "导出当前已保存版本",
"sidebar.exportWarningDesc": "这将导出您工作流的当前已保存版本。如果您在编辑器中有未保存的更改,请先使用工作流画布中的导出选项保存它们。",
"singleRun.back": "返回",

View File

@ -1025,7 +1025,9 @@
"publishLimit.startNodeTitlePrefix": "升級以",
"publishLimit.startNodeTitleSuffix": "解鎖無限開始節點",
"sandboxMigrationModal.description": "這將建立您的應用程式的獨立副本,不會影響原應用程式。",
"sandboxMigrationModal.dismiss": "暫不升級",
"sandboxMigrationModal.title": "升級到基於檔案系統的智能體",
"sandboxMigrationModal.upgrade": "複製並升級",
"sidebar.exportWarning": "導出當前保存的版本",
"sidebar.exportWarningDesc": "這將導出當前保存的工作流程版本。如果您在編輯器中有未保存的更改,請先通過使用工作流程畫布中的導出選項來保存它們。",
"singleRun.back": "返回",