feat(ui): change runtime selection component

This commit is contained in:
Harry 2026-01-09 18:02:28 +08:00
parent 78acfb0040
commit 95d62039b1
4 changed files with 71 additions and 47 deletions

View File

@ -1,7 +1,7 @@
'use client'
import type { AppIconSelection } from '../../base/app-icon-picker'
import { RiArrowRightLine, RiArrowRightSLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react'
import { RiArrowRightLine, RiArrowRightSLine, RiCheckLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react'
import { useDebounceFn, useKeyPress } from 'ahooks'
import Image from 'next/image'
@ -12,11 +12,13 @@ import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { trackEvent } from '@/app/components/base/amplitude'
import AppIcon from '@/app/components/base/app-icon'
import Badge from '@/app/components/base/badge'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import FullScreenModal from '@/app/components/base/fullscreen-modal'
import { BubbleTextMod, ChatBot, ListSparkle, Logic } from '@/app/components/base/icons/src/vender/solid/communication'
import Input from '@/app/components/base/input'
import CustomSelect from '@/app/components/base/select/custom'
import Textarea from '@/app/components/base/textarea'
import { ToastContext } from '@/app/components/base/toast'
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
@ -41,6 +43,13 @@ type CreateAppProps = {
type RuntimeMode = 'classical' | 'new'
type RuntimeOption = {
label: string
value: RuntimeMode
description: string
recommended?: boolean
}
const WORKFLOW_RUNTIME_STORAGE_KEY_PREFIX = 'workflow:sandbox-runtime:'
function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }: CreateAppProps) {
@ -275,45 +284,51 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }:
<div className="system-sm-semibold mb-2 text-text-secondary">
{t('newApp.runtimeLabel', { ns: 'app' })}
</div>
<div className="flex gap-3">
<button
type="button"
className={cn(
'flex h-10 flex-1 items-center gap-2 rounded-xl border border-components-option-card-option-border bg-components-option-card-option-bg px-3',
runtimeMode === 'new' && 'border-components-option-card-option-border-selected bg-components-option-card-option-selected-bg',
)}
onClick={() => setRuntimeMode('new')}
>
<div
className={cn(
'h-4 w-4 rounded-full border border-components-radio-border bg-components-radio-bg shadow-xs',
runtimeMode === 'new' && 'border-[5px] border-components-radio-border-checked',
<CustomSelect<RuntimeOption>
options={[
{
label: t('newApp.runtimeOptionNew', { ns: 'app' }),
value: 'new',
description: t('newApp.runtimeOptionNewDescription', { ns: 'app' }),
recommended: true,
},
{
label: t('newApp.runtimeOptionClassical', { ns: 'app' }),
value: 'classical',
description: t('newApp.runtimeOptionClassicalDescription', { ns: 'app' }),
},
]}
value={runtimeMode}
onChange={value => setRuntimeMode(value as RuntimeMode)}
triggerProps={{
className: '!h-8 !rounded-lg !bg-components-input-bg-normal !px-2 !py-1',
}}
popupProps={{
wrapperClassName: 'z-[60]',
className: 'w-full',
itemClassName: '!h-auto !py-2 !items-start',
}}
CustomOption={(option, selected) => (
<>
<RiCheckLine className={cn(
'mr-2 h-4 w-4 shrink-0 text-text-accent',
!selected && 'opacity-0',
)}
/>
<div className="system-sm-medium text-text-secondary">
{t('newApp.runtimeOptionNew', { ns: 'app' })}
</div>
</button>
<button
type="button"
className={cn(
'flex h-10 flex-1 items-center gap-2 rounded-xl border border-components-option-card-option-border bg-components-option-card-option-bg px-3',
runtimeMode === 'classical' && 'border-components-option-card-option-border-selected bg-components-option-card-option-selected-bg',
)}
onClick={() => setRuntimeMode('classical')}
>
<div
className={cn(
'h-4 w-4 rounded-full border border-components-radio-border bg-components-radio-bg shadow-xs',
runtimeMode === 'classical' && 'border-[5px] border-components-radio-border-checked',
)}
/>
<div className="system-sm-medium text-text-secondary">
{t('newApp.runtimeOptionClassical', { ns: 'app' })}
</div>
</button>
</div>
/>
<div className="flex flex-1 flex-col gap-0.5">
<div className="flex items-center gap-1">
<span className="system-sm-semibold text-text-secondary">{option.label}</span>
{option.recommended && (
<Badge className="!h-4 !px-1">
{t('newApp.recommended', { ns: 'app' })}
</Badge>
)}
</div>
<span className="system-xs-regular text-text-tertiary">{option.description}</span>
</div>
</>
)}
/>
</div>
)}

View File

@ -174,9 +174,12 @@
"newApp.noTemplateFoundTip": "Try searching using different keywords.",
"newApp.optional": "Optional",
"newApp.previewDemo": "Preview demo",
"newApp.recommended": "RECOMMENDED",
"newApp.runtimeLabel": "Runtime",
"newApp.runtimeOptionClassical": "Classical",
"newApp.runtimeOptionNew": "Recommend",
"newApp.runtimeOptionClassical": "Classic",
"newApp.runtimeOptionClassicalDescription": "Classic runtime for compatibility, without Skill support",
"newApp.runtimeOptionNew": "Sandboxed",
"newApp.runtimeOptionNewDescription": "Secure runtime with Skill support",
"newApp.showTemplates": "I want to choose from a template",
"newApp.startFromBlank": "Create from Blank",
"newApp.startFromTemplate": "Create from Template",

View File

@ -173,9 +173,12 @@
"newApp.noTemplateFoundTip": "別のキーワードを使用して検索してみてください。",
"newApp.optional": "任意",
"newApp.previewDemo": "デモをプレビュー",
"newApp.runtimeLabel": "Runtime",
"newApp.runtimeOptionClassical": "Classical",
"newApp.runtimeOptionNew": "推奨",
"newApp.recommended": "推奨",
"newApp.runtimeLabel": "ランタイム",
"newApp.runtimeOptionClassical": "クラシック",
"newApp.runtimeOptionClassicalDescription": "互換性のあるクラシックランタイム、Skill非対応",
"newApp.runtimeOptionNew": "サンドボックス",
"newApp.runtimeOptionNewDescription": "Skill対応のセキュアランタイム",
"newApp.showTemplates": "テンプレートから選択したい",
"newApp.startFromBlank": "最初から作成",
"newApp.startFromTemplate": "テンプレートから作成",

View File

@ -173,9 +173,12 @@
"newApp.noTemplateFoundTip": "请尝试使用不同的关键字进行搜索。",
"newApp.optional": "可选",
"newApp.previewDemo": "预览 Demo",
"newApp.runtimeLabel": "Runtime",
"newApp.runtimeOptionClassical": "Classical",
"newApp.runtimeOptionNew": "推荐",
"newApp.recommended": "推荐",
"newApp.runtimeLabel": "运行时",
"newApp.runtimeOptionClassical": "经典版",
"newApp.runtimeOptionClassicalDescription": "经典运行时,兼容性好,不支持 Skill",
"newApp.runtimeOptionNew": "沙箱版",
"newApp.runtimeOptionNewDescription": "安全运行时,支持 Skill",
"newApp.showTemplates": "我想从范例模板中选择",
"newApp.startFromBlank": "创建空白应用",
"newApp.startFromTemplate": "从应用模板创建",