From b5d843b1fd07208d19e8704efac74ee8f0f15ef3 Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 23 Jan 2026 15:50:06 +0800 Subject: [PATCH] feat: combine 2 export --- .../components/app/create-app-modal/index.tsx | 5 +- .../app/log-annotation/index.spec.tsx | 1 + .../app/switch-app-modal/index.spec.tsx | 1 + .../app/workflow-log/detail.spec.tsx | 1 + .../app/workflow-log/index.spec.tsx | 1 + .../components/app/workflow-log/list.spec.tsx | 1 + web/app/components/apps/app-card.spec.tsx | 5 +- web/app/components/apps/app-card.tsx | 67 +++++-------------- .../components/workflow-header/index.spec.tsx | 1 + web/i18n/en-US/app.json | 6 +- web/i18n/zh-Hans/app.json | 6 +- web/types/app.ts | 2 + 12 files changed, 33 insertions(+), 64 deletions(-) diff --git a/web/app/components/app/create-app-modal/index.tsx b/web/app/components/app/create-app-modal/index.tsx index 1081973d17..31a0762d27 100644 --- a/web/app/components/app/create-app-modal/index.tsx +++ b/web/app/components/app/create-app-modal/index.tsx @@ -1,8 +1,9 @@ 'use client' import type { AppIconSelection } from '../../base/app-icon-picker' -import { RiArrowRightLine, RiArrowRightSLine, RiCheckLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react' +import type { RuntimeMode } from '@/types/app' +import { RiArrowRightLine, RiArrowRightSLine, RiCheckLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react' import { useDebounceFn, useKeyPress } from 'ahooks' import Image from 'next/image' import { useRouter } from 'next/navigation' @@ -39,8 +40,6 @@ type CreateAppProps = { defaultAppMode?: AppModeEnum } -type RuntimeMode = 'sandboxed' | 'classic' - type RuntimeOption = { label: string value: RuntimeMode diff --git a/web/app/components/app/log-annotation/index.spec.tsx b/web/app/components/app/log-annotation/index.spec.tsx index c7c654e870..14b2c6ce87 100644 --- a/web/app/components/app/log-annotation/index.spec.tsx +++ b/web/app/components/app/log-annotation/index.spec.tsx @@ -42,6 +42,7 @@ const createMockApp = (overrides: Partial = {}): App => ({ icon_url: null, use_icon_as_answer_icon: false, mode: AppModeEnum.CHAT, + runtime_type: 'classic' as const, enable_site: true, enable_api: true, api_rpm: 60, diff --git a/web/app/components/app/switch-app-modal/index.spec.tsx b/web/app/components/app/switch-app-modal/index.spec.tsx index f0400f8b75..14607a1c95 100644 --- a/web/app/components/app/switch-app-modal/index.spec.tsx +++ b/web/app/components/app/switch-app-modal/index.spec.tsx @@ -89,6 +89,7 @@ const createMockApp = (overrides: Partial = {}): App => ({ icon_url: null, use_icon_as_answer_icon: false, mode: AppModeEnum.COMPLETION, + runtime_type: 'classic' as const, enable_site: true, enable_api: true, api_rpm: 60, diff --git a/web/app/components/app/workflow-log/detail.spec.tsx b/web/app/components/app/workflow-log/detail.spec.tsx index 1ed7193d42..c3110ac4b5 100644 --- a/web/app/components/app/workflow-log/detail.spec.tsx +++ b/web/app/components/app/workflow-log/detail.spec.tsx @@ -69,6 +69,7 @@ const createMockApp = (overrides: Partial = {}): App => ({ icon_url: null, use_icon_as_answer_icon: false, mode: 'workflow' as AppModeEnum, + runtime_type: 'classic' as const, enable_site: true, enable_api: true, api_rpm: 60, diff --git a/web/app/components/app/workflow-log/index.spec.tsx b/web/app/components/app/workflow-log/index.spec.tsx index f8e3f16e25..2ae2029e09 100644 --- a/web/app/components/app/workflow-log/index.spec.tsx +++ b/web/app/components/app/workflow-log/index.spec.tsx @@ -170,6 +170,7 @@ const createMockApp = (overrides: Partial = {}): App => ({ icon_url: null, use_icon_as_answer_icon: false, mode: 'workflow' as AppModeEnum, + runtime_type: 'classic' as const, enable_site: true, enable_api: true, api_rpm: 60, diff --git a/web/app/components/app/workflow-log/list.spec.tsx b/web/app/components/app/workflow-log/list.spec.tsx index 760d222692..b2493b0477 100644 --- a/web/app/components/app/workflow-log/list.spec.tsx +++ b/web/app/components/app/workflow-log/list.spec.tsx @@ -101,6 +101,7 @@ const createMockApp = (overrides: Partial = {}): App => ({ icon_url: null, use_icon_as_answer_icon: false, mode: 'workflow' as AppModeEnum, + runtime_type: 'classic' as const, enable_site: true, enable_api: true, api_rpm: 60, diff --git a/web/app/components/apps/app-card.spec.tsx b/web/app/components/apps/app-card.spec.tsx index a9012dbbe8..feab513dc1 100644 --- a/web/app/components/apps/app-card.spec.tsx +++ b/web/app/components/apps/app-card.spec.tsx @@ -2,13 +2,13 @@ import type { Mock } from 'vitest' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import * as React from 'react' import { AccessMode } from '@/models/access-control' + // Mock API services - import for direct manipulation import * as appsService from '@/service/apps' - import * as exploreService from '@/service/explore' import * as workflowService from '@/service/workflow' -import { AppModeEnum } from '@/types/app' +import { AppModeEnum } from '@/types/app' // Import component after mocks import AppCard from './app-card' @@ -212,6 +212,7 @@ const createMockApp = (overrides: Record = {}) => ({ name: 'Test App', description: 'Test app description', mode: AppModeEnum.CHAT, + runtime_type: 'classic' as const, icon: '🤖', icon_type: 'emoji' as const, icon_background: '#FFEAD5', diff --git a/web/app/components/apps/app-card.tsx b/web/app/components/apps/app-card.tsx index 3dc48f93d6..23b134e5a7 100644 --- a/web/app/components/apps/app-card.tsx +++ b/web/app/components/apps/app-card.tsx @@ -157,6 +157,14 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { const onExport = async (include = false) => { try { + const isDownLoadBundle = app.runtime_type === 'sandboxed' + if (isDownLoadBundle) { + await exportAppBundle({ + appID: app.id, + include, + }) + return + } const { data } = await exportAppConfig({ appID: app.id, include, @@ -165,12 +173,15 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { const file = new Blob([data], { type: 'application/yaml' }) const url = URL.createObjectURL(file) a.href = url - a.download = `${app.name}.yml` + a.download = `${app.name}.${isDownLoadBundle ? 'zip' : 'yaml'}` a.click() URL.revokeObjectURL(url) } catch { - notify({ type: 'error', message: t('exportFailed', { ns: 'app' }) }) + notify({ + type: 'error', + message: t('exportFailed', { ns: 'app' }), + }) } } @@ -189,41 +200,11 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { setSecretEnvList(list) } catch { - notify({ type: 'error', message: t('exportFailed', { ns: 'app' }) }) - } - } - - const onExportBundle = async (include = false) => { - try { - await exportAppBundle({ - appID: app.id, - include, + notify({ + type: 'error', + message: t('exportFailed', { ns: 'app' }), }) } - catch { - notify({ type: 'error', message: t('exportBundleFailed', { ns: 'app' }) }) - } - } - - const [secretEnvListForBundle, setSecretEnvListForBundle] = useState([]) - - const exportBundleCheck = async () => { - if (app.mode !== AppModeEnum.WORKFLOW && app.mode !== AppModeEnum.ADVANCED_CHAT) { - onExportBundle() - return - } - try { - const workflowDraft = await fetchWorkflowDraft(`/apps/${app.id}/workflows/draft`) - const list = (workflowDraft.environment_variables || []).filter(env => env.value_type === 'secret') - if (list.length === 0) { - onExportBundle() - return - } - setSecretEnvListForBundle(list) - } - catch { - notify({ type: 'error', message: t('exportBundleFailed', { ns: 'app' }) }) - } } const onSwitch = () => { @@ -261,12 +242,6 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { e.preventDefault() exportCheck() } - const onClickExportBundle = async (e: React.MouseEvent) => { - e.stopPropagation() - props.onClick?.() - e.preventDefault() - exportBundleCheck() - } const onClickSwitch = async (e: React.MouseEvent) => { e.stopPropagation() props.onClick?.() @@ -317,9 +292,6 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { - {(app.mode === AppModeEnum.COMPLETION || app.mode === AppModeEnum.CHAT) && ( <> @@ -556,13 +528,6 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { onClose={() => setSecretEnvList([])} /> )} - {secretEnvListForBundle.length > 0 && ( - setSecretEnvListForBundle([])} - /> - )} {showAccessControl && ( setShowAccessControl(false)} /> )} diff --git a/web/app/components/workflow-app/components/workflow-header/index.spec.tsx b/web/app/components/workflow-app/components/workflow-header/index.spec.tsx index eb3148498f..88aeb77a8a 100644 --- a/web/app/components/workflow-app/components/workflow-header/index.spec.tsx +++ b/web/app/components/workflow-app/components/workflow-header/index.spec.tsx @@ -19,6 +19,7 @@ const createMockApp = (overrides: Partial = {}): App => ({ icon_url: null, use_icon_as_answer_icon: false, mode: AppModeEnum.COMPLETION, + runtime_type: 'classic' as const, enable_site: true, enable_api: true, api_rpm: 60, diff --git a/web/i18n/en-US/app.json b/web/i18n/en-US/app.json index b99b5e19cb..9fab3f0718 100644 --- a/web/i18n/en-US/app.json +++ b/web/i18n/en-US/app.json @@ -45,10 +45,8 @@ "editAppTitle": "Edit App Info", "editDone": "App info updated", "editFailed": "Failed to update app info", - "export": "Export DSL", - "exportBundle": "Export Bundle", - "exportBundleFailed": "Export bundle failed.", - "exportFailed": "Export DSL failed.", + "export": "Export", + "exportFailed": "Export failed.", "gotoAnything.actions.accountDesc": "Navigate to account page", "gotoAnything.actions.communityDesc": "Open Discord community", "gotoAnything.actions.docDesc": "Open help documentation", diff --git a/web/i18n/zh-Hans/app.json b/web/i18n/zh-Hans/app.json index 7cfaad45e6..3c67ebb500 100644 --- a/web/i18n/zh-Hans/app.json +++ b/web/i18n/zh-Hans/app.json @@ -45,10 +45,8 @@ "editAppTitle": "编辑应用信息", "editDone": "应用信息已更新", "editFailed": "更新应用信息失败", - "export": "导出 DSL", - "exportBundle": "导出 Bundle", - "exportBundleFailed": "导出 Bundle 失败", - "exportFailed": "导出 DSL 失败", + "export": "导出", + "exportFailed": "导出 失败", "gotoAnything.actions.accountDesc": "导航到账户页面", "gotoAnything.actions.communityDesc": "打开 Discord 社区", "gotoAnything.actions.docDesc": "打开帮助文档", diff --git a/web/types/app.ts b/web/types/app.ts index c8c409a22c..55f7bbf4c8 100644 --- a/web/types/app.ts +++ b/web/types/app.ts @@ -317,6 +317,7 @@ export type SiteConfig = { } export type AppIconType = 'image' | 'emoji' | 'link' +export type RuntimeMode = 'sandboxed' | 'classic' /** * App @@ -347,6 +348,7 @@ export type App = { /** Mode */ mode: AppModeEnum + runtime_type: RuntimeMode /** Enable web app */ enable_site: boolean /** Enable web API */