From 2ffbc3849ec9be02ba0a97a6ea9faad885132adc Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Thu, 15 Aug 2024 16:13:05 +0800 Subject: [PATCH 1/6] fix desktop api getBilling --- frontend/desktop/src/pages/api/desktop/getBilling.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/desktop/src/pages/api/desktop/getBilling.ts b/frontend/desktop/src/pages/api/desktop/getBilling.ts index e2e55cf0af2..1546bd0468c 100644 --- a/frontend/desktop/src/pages/api/desktop/getBilling.ts +++ b/frontend/desktop/src/pages/api/desktop/getBilling.ts @@ -33,9 +33,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) method: 'POST', body: JSON.stringify({ endTime: currentTime, - kubeConfig: kc.exportConfig(), - appType: '', - namespace, + kubeConfig: realKc, + // appType: '', + // namespace, startTime: timeOneMonthAgo }) }) @@ -45,9 +45,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) method: 'POST', body: JSON.stringify({ endTime: currentTime, - kubeConfig: kc.exportConfig(), - appType: '', - namespace, + kubeConfig: realKc, + // appType: '', + // namespace, startTime: time24HoursAgo }) }) From b8b4d7875589497c74a0dd7c870ea9ad690f6150 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Thu, 15 Aug 2024 16:14:48 +0800 Subject: [PATCH 2/6] feat:db tag --- .../dbprovider/public/locales/en/common.json | 7 +- .../dbprovider/public/locales/zh/common.json | 5 +- .../providers/dbprovider/src/constants/db.ts | 25 ++++++- .../db/detail/components/AppBaseInfo.tsx | 26 +++---- .../pages/db/detail/components/DelModal.tsx | 47 +++++++----- .../src/pages/db/detail/components/Header.tsx | 26 ++++++- .../db/detail/components/UpdateModal.tsx | 71 +++++++++++++++++++ .../src/pages/dbs/components/dbList.tsx | 39 ++++++++-- .../dbprovider/src/types/cluster.d.ts | 1 + .../providers/dbprovider/src/types/db.d.ts | 10 +++ .../providers/dbprovider/src/utils/adapt.ts | 42 +++++++++-- 11 files changed, 252 insertions(+), 47 deletions(-) create mode 100644 frontend/providers/dbprovider/src/pages/db/detail/components/UpdateModal.tsx diff --git a/frontend/providers/dbprovider/public/locales/en/common.json b/frontend/providers/dbprovider/public/locales/en/common.json index bbcd98798ea..5e01de48344 100644 --- a/frontend/providers/dbprovider/public/locales/en/common.json +++ b/frontend/providers/dbprovider/public/locales/en/common.json @@ -157,8 +157,9 @@ "delete_backup": "Delete Backup", "delete_failed": "Failed to delete", "delete_hint": "Warning: This will permanently delete all data in the database. Confirm to proceed.", + "delete_sealaf_app_tip": "The database is deployed via cloud development. \nSimply deleting the database does not clear out all components of your app, which may still incur charges. \nTo completely uninstall the app and clean all related components, uninstall the entire app in cloud development.", "delete_successful": "Deleted successfully", - "delete_template_app_tip": "To fully remove this app and all its components, please uninstall it directly from the App Store.", + "delete_template_app_tip": "The database is deployed via the app store. \nSimply deleting the database does not clear out all components of your app, which may still incur charges. \nTo completely uninstall the database and clean all related components, uninstall the entire app in the App Store.", "delete_warning": "Delete Warning", "deploy": "Deploy", "deploy_database": "Deploy DataBase", @@ -254,6 +255,7 @@ "restore_success": "Backup restored successfully", "rollbacks_per_second": "Rollbacks/s", "running_time": "Uptime", + "sealaf": "sealaf", "select_a_maximum_of_10_files": "Select up to 10 files", "service_deletion_failed": "Failed to delete the service", "set_auto_backup_successful": "Automatic backup task set successfully", @@ -279,10 +281,11 @@ "update": "Update", "update_database": "Update DataBase", "update_failed": "Update Failed", + "update_sealaf_app_tip": "The database is deployed through cloud development. To change the database, please go to cloud development.", "update_successful": "Update succeeded", "update_time": "Update Time", "upload_dump_file": "Upload Dump File", "use_docs": "Documentation", "version": "Version", "yaml_file": "YAML" -} \ No newline at end of file +} diff --git a/frontend/providers/dbprovider/public/locales/zh/common.json b/frontend/providers/dbprovider/public/locales/zh/common.json index aed52f2cb00..ed744ecd1e5 100644 --- a/frontend/providers/dbprovider/public/locales/zh/common.json +++ b/frontend/providers/dbprovider/public/locales/zh/common.json @@ -157,8 +157,9 @@ "delete_backup": "删除备份", "delete_failed": "删除出现意外", "delete_hint": "如果确认要删除这个数据库吗?如果执行此操作,将删除该数据库的所有数据。", + "delete_sealaf_app_tip": "该数据库是通过云开发部署的。仅删除数据库无法清除应用的所有组件,这些组件可能仍会产生费用。要彻底卸载应用并清理所有相关组件,请在云开发中卸载整个应用。", "delete_successful": "删除成功", - "delete_template_app_tip": "该应用是通过应用商店部署的,如果您想完全卸载该应用并清理所有相关的组件,请到应用商店中将整个应用删除。", + "delete_template_app_tip": "该数据库是通过应用商店部署的。仅删除数据库无法清除应用的所有组件,这些组件可能仍会产生费用。要彻底卸载数据库并清理所有相关组件,请在应用商店中卸载整个应用。", "delete_warning": "删除警告", "deploy": "部署", "deploy_database": "部署数据库", @@ -254,6 +255,7 @@ "restore_success": "恢复备份成功", "rollbacks_per_second": "回滚数", "running_time": "运行时长", + "sealaf": "云开发", "select_a_maximum_of_10_files": "最多选择 10 个文件", "service_deletion_failed": "Service 删除失败", "set_auto_backup_successful": "设置自动备份任务成功", @@ -279,6 +281,7 @@ "update": "变更", "update_database": "变更数据库", "update_failed": "更新失败", + "update_sealaf_app_tip": "该数据库是通过云开发部署的,变更该数据库请到云开发中进行。", "update_successful": "更新成功", "update_time": "更新时间", "upload_dump_file": "点击上传 Dump 文件", diff --git a/frontend/providers/dbprovider/src/constants/db.ts b/frontend/providers/dbprovider/src/constants/db.ts index 70099f0195d..e0aeea3dbf4 100644 --- a/frontend/providers/dbprovider/src/constants/db.ts +++ b/frontend/providers/dbprovider/src/constants/db.ts @@ -1,4 +1,11 @@ -import { DBEditType, DBDetailType, PodDetailType, DBType, ReconfigStatusMapType } from '@/types/db'; +import { + DBEditType, + DBDetailType, + PodDetailType, + DBType, + ReconfigStatusMapType, + DBSourceType +} from '@/types/db'; import { CpuSlideMarkList, MemorySlideMarkList } from './editApp'; export const crLabelKey = 'sealos-db-provider-cr'; @@ -9,6 +16,7 @@ export const SealosMigrationTaskLabel = 'datamigration.sealos.io/file-migration- export const MigrationRemark = 'migration-remark'; export const DBPreviousConfigKey = 'cloud.sealos.io/previous-config'; export const templateDeployKey = 'cloud.sealos.io/deploy-on-sealos'; +export const sealafDeployKey = 'sealaf-app'; export const DBReconfigureKey = 'ops.kubeblocks.io/ops-type=Reconfiguring'; export enum DBTypeEnum { @@ -271,7 +279,12 @@ export const defaultDBDetail: DBDetailType = { status: dbStatusMap.Creating, conditions: [], isDiskSpaceOverflow: false, - labels: {} + labels: {}, + source: { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + } }; export const defaultPod: PodDetailType = { @@ -406,3 +419,11 @@ export const DBReconfigureMap: { reconfigureKey: '' } }; + +export const DBSourceConfigs: Array<{ + key: string; + type: DBSourceType; +}> = [ + { key: templateDeployKey, type: 'app_store' }, + { key: sealafDeployKey, type: 'sealaf' } +]; diff --git a/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx b/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx index d03ed3eb7bb..040a0342e9d 100644 --- a/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx +++ b/frontend/providers/dbprovider/src/pages/db/detail/components/AppBaseInfo.tsx @@ -6,7 +6,7 @@ import { getDBStatefulSetByName } from '@/api/db'; import MyIcon from '@/components/Icon'; -import { DBTypeEnum, DBTypeSecretMap, defaultDBDetail, templateDeployKey } from '@/constants/db'; +import { DBTypeEnum, DBTypeSecretMap, defaultDBDetail } from '@/constants/db'; import useEnvStore from '@/store/env'; import { SOURCE_PRICE } from '@/store/static'; import type { DBDetailType } from '@/types/db'; @@ -30,7 +30,7 @@ import { } from '@chakra-ui/react'; import { MyTooltip, SealosCoin, useMessage } from '@sealos/ui'; import { useQuery } from '@tanstack/react-query'; -import { has, pick } from 'lodash'; +import { pick } from 'lodash'; import { useTranslation } from 'next-i18next'; import { useCallback, useMemo, useState } from 'react'; import { sealosApp } from 'sealos-desktop-sdk/app'; @@ -44,12 +44,6 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => { const { isOpen, onOpen, onClose } = useDisclosure(); const { message: toast } = useMessage(); - const [hasApplicationSource, sourceName] = useMemo(() => { - return db?.labels - ? [has(db.labels, templateDeployKey), db.labels[templateDeployKey]] - : [false, '']; - }, [db.labels]); - const supportConnectDB = useMemo(() => { return !!['postgresql', 'mongodb', 'apecloud-mysql', 'redis', 'milvus'].find( (item) => item === db.dbType @@ -216,7 +210,7 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => { return ( - {hasApplicationSource && ( + {db?.source?.hasSource && ( @@ -230,17 +224,25 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => { }} cursor={'pointer'} onClick={() => { - if (sourceName) { + if (!db.source.sourceName) return; + if (db.source.sourceType === 'app_store') { sealosApp.runEvents('openDesktopApp', { appKey: 'system-template', pathname: '/instance', - query: { instanceName: sourceName } + query: { instanceName: db.source.sourceName } + }); + } + if (db.source.sourceType === 'sealaf') { + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-sealaf', + pathname: '/', + query: { instanceName: db.source.sourceName } }); } }} > - {t('app_store')} + {t(db.source.sourceType)} {t('manage_all_resources')} diff --git a/frontend/providers/dbprovider/src/pages/db/detail/components/DelModal.tsx b/frontend/providers/dbprovider/src/pages/db/detail/components/DelModal.tsx index c2fa20ef72c..8d2e7167507 100644 --- a/frontend/providers/dbprovider/src/pages/db/detail/components/DelModal.tsx +++ b/frontend/providers/dbprovider/src/pages/db/detail/components/DelModal.tsx @@ -1,6 +1,7 @@ import { delDBByName } from '@/api/db'; import MyIcon from '@/components/Icon'; -import { templateDeployKey } from '@/constants/db'; +import { DBSource, DBSourceType } from '@/types/db'; +import { I18nCommonKey } from '@/types/i18next'; import { Box, Button, @@ -15,7 +16,6 @@ import { ModalOverlay } from '@chakra-ui/react'; import { useMessage } from '@sealos/ui'; -import { has } from 'lodash'; import { useTranslation } from 'next-i18next'; import { useCallback, useEffect, useRef, useState } from 'react'; import { sealosApp } from 'sealos-desktop-sdk/app'; @@ -29,12 +29,12 @@ const DelModal = ({ dbName, onClose, onSuccess, - labels + source }: { dbName: string; onClose: () => void; onSuccess: () => void; - labels: { [key: string]: string }; + source?: DBSource; }) => { const { t } = useTranslation(); const [inputValue, setInputValue] = useState(''); @@ -45,10 +45,14 @@ const DelModal = ({ useEffect(() => { if (!pageManuallyChangedRef.current) { - const hasApplicationSource = has(labels, templateDeployKey); - hasApplicationSource ? setActivePage(Page.REMINDER) : setActivePage(Page.DELETION_WARNING); + source?.hasSource ? setActivePage(Page.REMINDER) : setActivePage(Page.DELETION_WARNING); } - }, [labels]); + }, [source]); + + const deleteTypeTipMap: Record = { + app_store: t('delete_template_app_tip'), + sealaf: t('delete_sealaf_app_tip') + }; const handleDelApp = useCallback(async () => { try { @@ -71,14 +75,21 @@ const DelModal = ({ }, [dbName, toast, t, onSuccess, onClose]); const openTemplateApp = () => { - if (!labels) return; - const sourceName = labels[templateDeployKey]; - sealosApp.runEvents('openDesktopApp', { - appKey: 'system-template', - pathname: '/instance', - query: { instanceName: sourceName }, - messageData: { type: 'InternalAppCall', name: sourceName } - }); + if (!source?.hasSource) return; + if (source?.sourceType === 'app_store') { + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-template', + pathname: '/instance', + query: { instanceName: source?.sourceName } + }); + } + if (source?.sourceType === 'sealaf') { + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-sealaf', + pathname: '/', + query: { instanceName: source?.sourceName } + }); + } onClose(); }; @@ -95,7 +106,9 @@ const DelModal = ({ - {activePage === Page.REMINDER ? t('delete_template_app_tip') : t('delete_hint')} + {activePage === Page.REMINDER && source?.sourceType + ? deleteTypeTipMap[source?.sourceType] + : t('delete_hint')} {activePage === Page.DELETION_WARNING && ( @@ -127,7 +140,7 @@ const DelModal = ({ {t('Cancel')} - {activePage === Page.REMINDER && ( + {activePage === Page.REMINDER && source?.sourceType !== 'sealaf' && ( + + + + + + ); +}; + +export default UpdateModal; diff --git a/frontend/providers/dbprovider/src/pages/dbs/components/dbList.tsx b/frontend/providers/dbprovider/src/pages/dbs/components/dbList.tsx index 2d320cbaba2..711be4593ed 100644 --- a/frontend/providers/dbprovider/src/pages/dbs/components/dbList.tsx +++ b/frontend/providers/dbprovider/src/pages/dbs/components/dbList.tsx @@ -3,11 +3,21 @@ import DBStatusTag from '@/components/DBStatusTag'; import MyIcon from '@/components/Icon'; import { DBComponentNameMap, DBStatusEnum } from '@/constants/db'; import { useConfirm } from '@/hooks/useConfirm'; +import UpdateModal from '@/pages/db/detail/components/UpdateModal'; import useEnvStore from '@/store/env'; import { useGlobalStore } from '@/store/global'; import { DBListItemType } from '@/types/db'; import { printMemory } from '@/utils/tools'; -import { Box, Button, Center, Flex, Image, MenuButton, useTheme } from '@chakra-ui/react'; +import { + Box, + Button, + Center, + Flex, + Image, + MenuButton, + useDisclosure, + useTheme +} from '@chakra-ui/react'; import { MyTable, SealosMenu, useMessage } from '@sealos/ui'; import { useTranslation } from 'next-i18next'; import dynamic from 'next/dynamic'; @@ -29,8 +39,14 @@ const DBList = ({ const theme = useTheme(); const router = useRouter(); const { SystemEnv } = useEnvStore(); - + const { + isOpen: isOpenUpdateModal, + onOpen: onOpenUpdateModal, + onClose: onCloseUpdateModal + } = useDisclosure(); const [delAppName, setDelAppName] = useState(''); + const [updateAppName, setUpdateAppName] = useState(''); + const { openConfirm: onOpenPause, ConfirmChild: PauseChild } = useConfirm({ content: t('pause_hint') }); @@ -202,7 +218,14 @@ const DBList = ({ {t('update')} ), - onClick: () => router.push(`/db/edit?name=${item.name}`), + onClick: () => { + if (item.source.hasSource && item.source.sourceType === 'sealaf') { + setUpdateAppName(item.name); + onOpenUpdateModal(); + } else { + router.push(`/db/edit?name=${item.name}`); + } + }, isDisabled: item.status.value === 'Updating' && !item.isDiskSpaceOverflow }, { @@ -299,12 +322,20 @@ const DBList = ({ {!!delAppName && ( item.name === delAppName)?.labels || {}} + source={dbList.find((i) => i.name === delAppName)?.source} dbName={delAppName} onClose={() => setDelAppName('')} onSuccess={refetchApps} /> )} + i.name === updateAppName)?.source} + isOpen={isOpenUpdateModal} + onClose={() => { + setUpdateAppName(''); + onCloseUpdateModal(); + }} + /> ); }; diff --git a/frontend/providers/dbprovider/src/types/cluster.d.ts b/frontend/providers/dbprovider/src/types/cluster.d.ts index f4f1a851170..c75d11ec549 100644 --- a/frontend/providers/dbprovider/src/types/cluster.d.ts +++ b/frontend/providers/dbprovider/src/types/cluster.d.ts @@ -10,6 +10,7 @@ export type KbPgClusterType = { 'clusterdefinition.kubeblocks.io/name': `${DBTypeEnum}`; 'clusterversion.kubeblocks.io/name': string; 'sealos-db-provider/postgresql': string; + [key: string]: string; }; name: string; namespace: string; diff --git a/frontend/providers/dbprovider/src/types/db.d.ts b/frontend/providers/dbprovider/src/types/db.d.ts index 5946b8c4eb3..e2f6775fba2 100644 --- a/frontend/providers/dbprovider/src/types/db.d.ts +++ b/frontend/providers/dbprovider/src/types/db.d.ts @@ -56,6 +56,7 @@ export interface DBListItemType { conditions: DBConditionItemType[]; isDiskSpaceOverflow: boolean; labels: { [key: string]: string }; + source: DBSource; } export interface DBEditType { @@ -68,6 +69,14 @@ export interface DBEditType { storage: number; } +export type DBSourceType = 'app_store' | 'sealaf'; + +export type DBSource = { + hasSource: boolean; + sourceName: string; + sourceType: DBSourceType; +}; + export interface DBDetailType extends DBEditType { id: string; createTime: string; @@ -75,6 +84,7 @@ export interface DBDetailType extends DBEditType { conditions: DBConditionItemType[]; isDiskSpaceOverflow: boolean; labels: { [key: string]: string }; + source: DBSource; } export interface DBConditionItemType { diff --git a/frontend/providers/dbprovider/src/utils/adapt.ts b/frontend/providers/dbprovider/src/utils/adapt.ts index 69f64a8fa90..de52da7eb3b 100644 --- a/frontend/providers/dbprovider/src/utils/adapt.ts +++ b/frontend/providers/dbprovider/src/utils/adapt.ts @@ -1,12 +1,10 @@ import { BACKUP_REMARK_LABEL_KEY, BackupTypeEnum, backupStatusMap } from '@/constants/backup'; import { + DBPreviousConfigKey, DBReconfigStatusMap, - DBStatusEnum, - DBReconfigureMap, + DBSourceConfigs, MigrationRemark, - dbStatusMap, - DBReconfigureKey, - DBPreviousConfigKey + dbStatusMap } from '@/constants/db'; import type { AutoBackupFormType, BackupCRItemType } from '@/types/backup'; import type { @@ -18,6 +16,7 @@ import type { DBDetailType, DBEditType, DBListItemType, + DBSourceType, DBType, OpsRequestItemType, PodDetailType, @@ -35,8 +34,35 @@ import { } from '@/utils/tools'; import type { CoreV1EventList, V1Pod } from '@kubernetes/client-node'; import dayjs from 'dayjs'; +import { has } from 'lodash'; import type { BackupItemType } from '../types/db'; +export const getDBSource = ( + db: KbPgClusterType +): { + hasSource: boolean; + sourceName: string; + sourceType: DBSourceType; +} => { + const labels = db.metadata?.labels || {}; + + for (const config of DBSourceConfigs) { + if (has(labels, config.key)) { + return { + hasSource: true, + sourceName: labels[config.key], + sourceType: config.type + }; + } + } + + return { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + }; +}; + export const adaptDBListItem = (db: KbPgClusterType): DBListItemType => { // compute store amount return { @@ -55,7 +81,8 @@ export const adaptDBListItem = (db: KbPgClusterType): DBListItemType => { '-', conditions: db?.status?.conditions || [], isDiskSpaceOverflow: false, - labels: db.metadata.labels || {} + labels: db.metadata.labels || {}, + source: getDBSource(db) }; }; @@ -78,7 +105,8 @@ export const adaptDBDetail = (db: KbPgClusterType): DBDetailType => { ), conditions: db?.status?.conditions || [], isDiskSpaceOverflow: false, - labels: db.metadata.labels || {} + labels: db.metadata.labels || {}, + source: getDBSource(db) }; }; From 5868be57f75852eaf9464176538d70084d40f14b Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Thu, 15 Aug 2024 16:15:01 +0800 Subject: [PATCH 3/6] feat:launchpad tag --- .../applaunchpad/.vscode/settings.json | 2 - .../public/locales/en/common.json | 14 ++-- .../public/locales/zh/common.json | 10 ++- .../applaunchpad/src/constants/app.ts | 13 ++++ .../providers/applaunchpad/src/mock/apps.ts | 28 ++++++-- .../app/detail/components/AppBaseInfo.tsx | 55 +++++++------- .../pages/app/detail/components/DelModal.tsx | 46 +++++++----- .../pages/app/detail/components/Header.tsx | 31 ++++++-- .../app/detail/components/UpdateModal.tsx | 71 +++++++++++++++++++ .../src/pages/app/detail/index.tsx | 2 +- .../src/pages/apps/components/appList.tsx | 38 ++++++++-- .../providers/applaunchpad/src/types/app.d.ts | 10 ++- .../providers/applaunchpad/src/utils/adapt.ts | 40 +++++++++-- 13 files changed, 286 insertions(+), 74 deletions(-) create mode 100644 frontend/providers/applaunchpad/src/pages/app/detail/components/UpdateModal.tsx diff --git a/frontend/providers/applaunchpad/.vscode/settings.json b/frontend/providers/applaunchpad/.vscode/settings.json index 488915e5da7..8386db6721e 100644 --- a/frontend/providers/applaunchpad/.vscode/settings.json +++ b/frontend/providers/applaunchpad/.vscode/settings.json @@ -9,11 +9,9 @@ "ts" ], "i18n-ally.keystyle": "nested", - "i18n-ally.sortKeys": true, "i18n-ally.keepFulfilled": false, "i18n-ally.sourceLanguage": "zh", "i18n-ally.displayLanguage": "zh", - "i18n-ally.namespace": true, "i18n-ally.pathMatcher": "{locale}/{namespaces}.json", "i18n-ally.extract.targetPickingStrategy": "most-similar-by-key" } \ No newline at end of file diff --git a/frontend/providers/applaunchpad/public/locales/en/common.json b/frontend/providers/applaunchpad/public/locales/en/common.json index 0b8e10132db..b72f413054e 100644 --- a/frontend/providers/applaunchpad/public/locales/en/common.json +++ b/frontend/providers/applaunchpad/public/locales/en/common.json @@ -25,7 +25,7 @@ "Application paused": "Application Paused", "Application Type": "Type", "Applications": "Applications", - "Are you sure you want to delete the file or folder?": "Are you sure you want to delete this file\/folder?", + "Are you sure you want to delete the file or folder?": "Are you sure you want to delete this file/folder?", "Are you sure you want to delete this application? If you proceed, all data for this project will be deleted": "Are you sure you want to delete this application? All project data will be permanently lost if you proceed.", "Attribute": "Attribute", "Auto scaling": "Scaling", @@ -133,7 +133,7 @@ "Memory target value": "Target Memory Usage", "Min Storage Value": "Minimum size is", "mount path": "Mount path", - "Mount Path Auth": "Mount path must match: \/^[0-9a-zA-Z_\/][0-9a-zA-Z_\/.-]*[0-9a-zA-Z_\/]$\/", + "Mount Path Auth": "Mount path must match: /^[0-9a-zA-Z_/][0-9a-zA-Z_/.-]*[0-9a-zA-Z_/]$/", "Name": "Name", "Network Configuration": "Network", "Network port conflict": "Container port conflict", @@ -160,7 +160,7 @@ "Pause": "Pause", "pause_message": "Pausing the service will stop the calculation of charges for CPU and memory, but charges for storage and external network ports will still apply. Would you like to pause now?", "Paused": "Paused", - "Perday": "\/day", + "Perday": "/day", "Please confirm to restart the Pod?": "Are you sure you want to restart this pod?", "Please enter": "Please enter", "please enter app name": "please enter: {{appName}}", @@ -252,5 +252,9 @@ "Remind": "Remind", "Confirm to go": "Confirm to go", "Delete anyway": "Delete anyway", - "Delete Template App Tip": "To fully remove this app and all its components, please uninstall it directly from the App Store." -} \ No newline at end of file + "delete_template_app_tip": "The app is deployed via the app store. \nSimply deleting the app won't clear out all of the app's components, which may still accrue charges. \nTo completely uninstall an app and clean all related components, uninstall the entire app from the App Store.", + "delete_sealaf_app_tip": "The application is deployed via cloud development. \nSimply deleting the app won't clear out all of the app's components, which may still accrue charges. \nTo completely uninstall the app and clean all related components, uninstall the entire app in cloud development.", + "remind": "remind", + "update_sealaf_app_tip": "This application is deployed through cloud development. To change the application, please go to cloud development.", + "confirm_to_go": "Confirm to go" +} diff --git a/frontend/providers/applaunchpad/public/locales/zh/common.json b/frontend/providers/applaunchpad/public/locales/zh/common.json index 297942b50cd..58fd4670742 100644 --- a/frontend/providers/applaunchpad/public/locales/zh/common.json +++ b/frontend/providers/applaunchpad/public/locales/zh/common.json @@ -133,7 +133,7 @@ "Memory target value": "内存目标值", "Min Storage Value": "容量最小为", "mount path": "挂载路径", - "Mount Path Auth": "挂载路径格式须满足: \/^[0-9a-zA-Z_\/][0-9a-zA-Z_\/.-]*[0-9a-zA-Z_\/]$\/", + "Mount Path Auth": "挂载路径格式须满足: /^[0-9a-zA-Z_/][0-9a-zA-Z_/.-]*[0-9a-zA-Z_/]$/", "Name": "名字", "Network Configuration": "网络配置", "Network port conflict": "容器端口冲突", @@ -252,5 +252,9 @@ "Remind": "提醒", "Confirm to go": "确认前往", "Delete anyway": "仍要删除", - "Delete Template App Tip": "该应用是通过应用商店部署的,如果您想完全卸载该应用并清理所有相关的组件,请到应用商店中将整个应用删除。" -} \ No newline at end of file + "delete_template_app_tip": "该应用是通过应用商店部署的。仅删除应用无法清除应用的所有组件,这些组件可能仍会产生费用。要彻底卸载应用并清理所有相关组件,请在应用商店中卸载整个应用。", + "delete_sealaf_app_tip": "该应用是通过云开发部署的。仅删除应用无法清除应用的所有组件,这些组件可能仍会产生费用。要彻底卸载应用并清理所有相关组件,请在云开发中卸载整个应用。", + "remind": "提醒", + "update_sealaf_app_tip": "该应用是通过云开发部署的,变更该应用请到云开发中进行。", + "confirm_to_go": "确认前往" +} diff --git a/frontend/providers/applaunchpad/src/constants/app.ts b/frontend/providers/applaunchpad/src/constants/app.ts index 4eb512549ea..6868000cbc7 100644 --- a/frontend/providers/applaunchpad/src/constants/app.ts +++ b/frontend/providers/applaunchpad/src/constants/app.ts @@ -1,3 +1,5 @@ +import { TAppSourceType } from '@/types/app'; + export enum AppStatusEnum { running = 'running', creating = 'creating', @@ -85,8 +87,19 @@ export const appDeployKey = 'cloud.sealos.io/app-deploy-manager'; export const publicDomainKey = `cloud.sealos.io/app-deploy-manager-domain`; export const gpuNodeSelectorKey = 'nvidia.com/gpu.product'; export const gpuResourceKey = 'nvidia.com/gpu'; +export const templateDeployKey = 'cloud.sealos.io/deploy-on-sealos'; +export const sealafDeployKey = 'sealaf-app'; + export enum Coin { cny = 'cny', shellCoin = 'shellCoin', usd = 'usd' } + +export const AppSourceConfigs: Array<{ + key: string; + type: TAppSourceType; +}> = [ + { key: templateDeployKey, type: 'app_store' }, + { key: sealafDeployKey, type: 'sealaf' } +]; diff --git a/frontend/providers/applaunchpad/src/mock/apps.ts b/frontend/providers/applaunchpad/src/mock/apps.ts index 9b77b73fa2d..ae0b03fe78e 100644 --- a/frontend/providers/applaunchpad/src/mock/apps.ts +++ b/frontend/providers/applaunchpad/src/mock/apps.ts @@ -26,7 +26,12 @@ export const MOCK_APPS: AppListItemType[] = [ maxReplicas: 1, minReplicas: 1, storeAmount: 0, - labels: {} + labels: {}, + source: { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + } }, { id: 'string2', @@ -50,7 +55,12 @@ export const MOCK_APPS: AppListItemType[] = [ maxReplicas: 1, minReplicas: 1, storeAmount: 0, - labels: {} + labels: {}, + source: { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + } }, { id: 'string3', @@ -74,7 +84,12 @@ export const MOCK_APPS: AppListItemType[] = [ maxReplicas: 1, minReplicas: 1, storeAmount: 0, - labels: {} + labels: {}, + source: { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + } } ]; export const MOCK_NAMESPACE = 'ns-34dccadb-8e62-4205-8c1b-fc2dc146cd68'; @@ -272,5 +287,10 @@ export const MOCK_APP_DETAIL: AppDetailType = { serverAddress: '' }, storeList: [], - labels: {} + labels: {}, + source: { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + } }; diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx index b9d24f3e9e2..d9bf1fdf3f0 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx @@ -1,29 +1,28 @@ -import React, { useMemo, useState } from 'react'; +import GPUItem from '@/components/GPUItem'; +import MyIcon from '@/components/Icon'; +import { MOCK_APP_DETAIL } from '@/mock/apps'; +import { useUserStore } from '@/store/user'; +import type { AppDetailType } from '@/types/app'; +import { printMemory, useCopyData } from '@/utils/tools'; import { - Box, - Flex, - useTheme, - Tag, Accordion, AccordionButton, + AccordionIcon, AccordionItem, AccordionPanel, - AccordionIcon + Box, + Flex, + Tag, + useTheme } from '@chakra-ui/react'; -import type { AppDetailType } from '@/types/app'; -import { useCopyData, printMemory } from '@/utils/tools'; -import { useUserStore } from '@/store/user'; -import styles from '../index.module.scss'; -import dynamic from 'next/dynamic'; -const ConfigMapDetailModal = dynamic(() => import('./ConfigMapDetailModal')); -import { MOCK_APP_DETAIL } from '@/mock/apps'; -import { useTranslation } from 'next-i18next'; import { MyTooltip } from '@sealos/ui'; -import GPUItem from '@/components/GPUItem'; -import MyIcon from '@/components/Icon'; -import { has } from 'lodash'; -import { templateDeployKey } from '@/constants/account'; +import { useTranslation } from 'next-i18next'; +import dynamic from 'next/dynamic'; +import React, { useMemo, useState } from 'react'; import { sealosApp } from 'sealos-desktop-sdk/app'; +import styles from '../index.module.scss'; + +const ConfigMapDetailModal = dynamic(() => import('./ConfigMapDetailModal')); const AppBaseInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => { const { t } = useTranslation(); @@ -35,12 +34,6 @@ const AppBaseInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => { value: string; }>(); - const [hasApplicationSource, sourceName] = useMemo(() => { - return app?.labels - ? [has(app.labels, templateDeployKey), app.labels[templateDeployKey]] - : [false, '']; - }, [app.labels]); - const appInfoTable = useMemo< { name: string; @@ -106,7 +99,7 @@ const AppBaseInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => { return ( - {hasApplicationSource && ( + {app?.source?.hasSource && ( @@ -120,11 +113,19 @@ const AppBaseInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => { }} cursor={'pointer'} onClick={() => { - if (sourceName) { + if (!app?.source?.sourceName) return; + if (app.source.sourceType === 'app_store') { sealosApp.runEvents('openDesktopApp', { appKey: 'system-template', pathname: '/instance', - query: { instanceName: sourceName } + query: { instanceName: app.source.sourceName } + }); + } + if (app.source.sourceType === 'sealaf') { + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-sealaf', + pathname: '/', + query: { instanceName: app.source.sourceName } }); } }} diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx index 63a423dd774..37eb253fa06 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx @@ -1,6 +1,6 @@ import { delAppByName } from '@/api/app'; import MyIcon from '@/components/Icon'; -import { templateDeployKey } from '@/constants/account'; +import { TAppSource, TAppSourceType } from '@/types/app'; import { Box, Button, @@ -15,7 +15,6 @@ import { ModalOverlay } from '@chakra-ui/react'; import { useMessage } from '@sealos/ui'; -import { has } from 'lodash'; import { useTranslation } from 'next-i18next'; import { useCallback, useEffect, useRef, useState } from 'react'; import { sealosApp } from 'sealos-desktop-sdk/app'; @@ -29,12 +28,12 @@ const DelModal = ({ appName, onClose, onSuccess, - labels + source }: { appName: string; onClose: () => void; onSuccess: () => void; - labels: { [key: string]: string }; + source?: TAppSource; }) => { const { t } = useTranslation(); const [inputValue, setInputValue] = useState(''); @@ -45,10 +44,14 @@ const DelModal = ({ useEffect(() => { if (!pageManuallyChangedRef.current) { - const hasApplicationSource = has(labels, templateDeployKey); - hasApplicationSource ? setActivePage(Page.REMINDER) : setActivePage(Page.DELETION_WARNING); + source?.hasSource ? setActivePage(Page.REMINDER) : setActivePage(Page.DELETION_WARNING); } - }, [labels]); + }, [source]); + + const deleteTypeTipMap: Record = { + app_store: t('delete_template_app_tip'), + sealaf: t('delete_sealaf_app_tip') + }; const handleDelApp = useCallback(async () => { try { @@ -71,14 +74,21 @@ const DelModal = ({ }, [appName, toast, t, onSuccess, onClose]); const openTemplateApp = () => { - if (!labels) return; - const sourceName = labels[templateDeployKey]; - sealosApp.runEvents('openDesktopApp', { - appKey: 'system-template', - pathname: '/instance', - query: { instanceName: sourceName }, - messageData: { type: 'InternalAppCall', name: sourceName } - }); + if (!source?.hasSource) return; + if (source?.sourceType === 'app_store') { + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-template', + pathname: '/instance', + query: { instanceName: source?.sourceName } + }); + } + if (source?.sourceType === 'sealaf') { + sealosApp.runEvents('openDesktopApp', { + appKey: 'system-sealaf', + pathname: '/', + query: { instanceName: source?.sourceName } + }); + } onClose(); }; @@ -96,8 +106,8 @@ const DelModal = ({ - {activePage === Page.REMINDER - ? t('Delete Template App Tip') + {activePage === Page.REMINDER && source?.sourceType + ? deleteTypeTipMap[source?.sourceType] : t( 'Are you sure you want to delete this application? If you proceed, all data for this project will be deleted' )} @@ -125,7 +135,7 @@ const DelModal = ({ - {activePage === Page.REMINDER && ( + {activePage === Page.REMINDER && source?.sourceType !== 'sealaf' && ( + + + + + + ); +}; + +export default UpdateModal; diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/index.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/index.tsx index 4c68c5811d9..c9432e8e565 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/index.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/index.tsx @@ -79,7 +79,7 @@ const AppDetail = ({ appName }: { appName: string }) => { >
import('@/pages/app/detail/components/DelModal')); @@ -33,11 +43,16 @@ const AppList = ({ const { toast } = useToast(); const theme = useTheme(); const router = useRouter(); - const [delAppName, setDelAppName] = useState(''); + const [updateAppName, setUpdateAppName] = useState(''); const { openConfirm: onOpenPause, ConfirmChild: PauseChild } = useConfirm({ content: 'pause_message' }); + const { + isOpen: isOpenUpdateModal, + onOpen: onOpenUpdateModal, + onClose: onCloseUpdateModal + } = useDisclosure(); const handleRestartApp = useCallback( async (appName: string) => { @@ -277,7 +292,14 @@ const AppList = ({ ), - onClick: () => router.push(`/app/edit?name=${item.name}`) + onClick: () => { + if (item.source.hasSource && item.source.sourceType === 'sealaf') { + setUpdateAppName(item.name); + onOpenUpdateModal(); + } else { + router.push(`/app/edit?name=${item.name}`); + } + } }, { child: ( @@ -356,11 +378,19 @@ const AppList = ({ {!!delAppName && ( item.name === delAppName)?.labels || {}} + source={apps.find((item) => item.name === delAppName)?.source} onClose={() => setDelAppName('')} onSuccess={refetchApps} /> )} + i.name === updateAppName)?.source} + isOpen={isOpenUpdateModal} + onClose={() => { + setUpdateAppName(''); + onCloseUpdateModal(); + }} + /> ); }; diff --git a/frontend/providers/applaunchpad/src/types/app.d.ts b/frontend/providers/applaunchpad/src/types/app.d.ts index 18200eec8a5..6a1f8c825f1 100644 --- a/frontend/providers/applaunchpad/src/types/app.d.ts +++ b/frontend/providers/applaunchpad/src/types/app.d.ts @@ -56,6 +56,7 @@ export interface AppListItemType { maxReplicas: number; storeAmount: number; labels: { [key: string]: string }; + source: TAppSource; } export type ProtocolType = 'HTTP' | 'GRPC' | 'WS'; @@ -107,6 +108,13 @@ export interface AppEditType { }[]; } +export type TAppSourceType = 'app_store' | 'sealaf'; + +export type TAppSource = { + hasSource: boolean; + sourceName: string; + sourceType: TAppSourceType; +}; export interface AppDetailType extends AppEditType { id: string; createTime: string; @@ -117,7 +125,7 @@ export interface AppDetailType extends AppEditType { usedMemory: MonitorDataResult; crYamlList: DeployKindsType[]; labels: { [key: string]: string }; - + source: TAppSource; // pods: PodDetailType[]; } diff --git a/frontend/providers/applaunchpad/src/utils/adapt.ts b/frontend/providers/applaunchpad/src/utils/adapt.ts index 3b7f5ad86e9..bff96e334a9 100644 --- a/frontend/providers/applaunchpad/src/utils/adapt.ts +++ b/frontend/providers/applaunchpad/src/utils/adapt.ts @@ -19,7 +19,9 @@ import type { PodMetrics, PodEvent, HpaTarget, - ProtocolType + ProtocolType, + TAppSource, + TAppSourceType } from '@/types/app'; import { appStatusMap, @@ -30,16 +32,44 @@ import { PodStatusEnum, publicDomainKey, gpuNodeSelectorKey, - gpuResourceKey + gpuResourceKey, + AppSourceConfigs } from '@/constants/app'; import { cpuFormatToM, memoryFormatToMi, formatPodTime, atobSecretYaml } from '@/utils/tools'; import type { DeployKindsType, AppEditType } from '@/types/app'; import { defaultEditVal } from '@/constants/editApp'; import { customAlphabet } from 'nanoid'; import { getInitData } from '@/api/platform'; +import { has } from 'lodash'; const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 12); +export const getAppSource = ( + app: V1Deployment | V1StatefulSet +): { + hasSource: boolean; + sourceName: string; + sourceType: TAppSourceType; +} => { + const labels = app.metadata?.labels || {}; + + for (const config of AppSourceConfigs) { + if (has(labels, config.key)) { + return { + hasSource: true, + sourceName: labels[config.key], + sourceType: config.type + }; + } + } + + return { + hasSource: false, + sourceName: '', + sourceType: 'app_store' + }; +}; + export const adaptAppListItem = (app: V1Deployment & V1StatefulSet): AppListItemType => { // compute store amount const storeAmount = app.spec?.volumeClaimTemplates @@ -82,7 +112,8 @@ export const adaptAppListItem = (app: V1Deployment & V1StatefulSet): AppListItem maxReplicas: +(app.metadata?.annotations?.[maxReplicasKey] || app.status?.readyReplicas || 0), minReplicas: +(app.metadata?.annotations?.[minReplicasKey] || app.status?.readyReplicas || 0), storeAmount, - labels: app.metadata?.labels || {} + labels: app.metadata?.labels || {}, + source: getAppSource(app) }; }; @@ -329,7 +360,8 @@ export const adaptAppDetail = async (configs: DeployKindsType[]): Promise Date: Thu, 15 Aug 2024 17:00:07 +0800 Subject: [PATCH 4/6] fix useTranslation --- .../providers/applaunchpad/public/locales/en/common.json | 7 ++++--- .../providers/applaunchpad/public/locales/zh/common.json | 7 ++++--- .../src/pages/app/detail/components/AppBaseInfo.tsx | 2 +- .../src/pages/app/detail/components/DelModal.tsx | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/frontend/providers/applaunchpad/public/locales/en/common.json b/frontend/providers/applaunchpad/public/locales/en/common.json index b72f413054e..ae954091411 100644 --- a/frontend/providers/applaunchpad/public/locales/en/common.json +++ b/frontend/providers/applaunchpad/public/locales/en/common.json @@ -250,11 +250,12 @@ "App Store": "App Store", "Manage all resources": "Manage all resources", "Remind": "Remind", - "Confirm to go": "Confirm to go", "Delete anyway": "Delete anyway", "delete_template_app_tip": "The app is deployed via the app store. \nSimply deleting the app won't clear out all of the app's components, which may still accrue charges. \nTo completely uninstall an app and clean all related components, uninstall the entire app from the App Store.", "delete_sealaf_app_tip": "The application is deployed via cloud development. \nSimply deleting the app won't clear out all of the app's components, which may still accrue charges. \nTo completely uninstall the app and clean all related components, uninstall the entire app in cloud development.", "remind": "remind", "update_sealaf_app_tip": "This application is deployed through cloud development. To change the application, please go to cloud development.", - "confirm_to_go": "Confirm to go" -} + "confirm_to_go": "Confirm to go", + "app_store": "App Store", + "sealaf": "sealaf" +} \ No newline at end of file diff --git a/frontend/providers/applaunchpad/public/locales/zh/common.json b/frontend/providers/applaunchpad/public/locales/zh/common.json index 58fd4670742..cd69651166f 100644 --- a/frontend/providers/applaunchpad/public/locales/zh/common.json +++ b/frontend/providers/applaunchpad/public/locales/zh/common.json @@ -250,11 +250,12 @@ "App Store": "应用商店", "Manage all resources": "管理所有资源", "Remind": "提醒", - "Confirm to go": "确认前往", "Delete anyway": "仍要删除", "delete_template_app_tip": "该应用是通过应用商店部署的。仅删除应用无法清除应用的所有组件,这些组件可能仍会产生费用。要彻底卸载应用并清理所有相关组件,请在应用商店中卸载整个应用。", "delete_sealaf_app_tip": "该应用是通过云开发部署的。仅删除应用无法清除应用的所有组件,这些组件可能仍会产生费用。要彻底卸载应用并清理所有相关组件,请在云开发中卸载整个应用。", "remind": "提醒", "update_sealaf_app_tip": "该应用是通过云开发部署的,变更该应用请到云开发中进行。", - "confirm_to_go": "确认前往" -} + "confirm_to_go": "确认前往", + "sealaf": "云开发", + "app_store": "应用商店" +} \ No newline at end of file diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx index d9bf1fdf3f0..89f98aae550 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/AppBaseInfo.tsx @@ -131,7 +131,7 @@ const AppBaseInfo = ({ app = MOCK_APP_DETAIL }: { app: AppDetailType }) => { }} > - {t('App Store')} + {t(app.source?.sourceType)} {t('Manage all resources')} diff --git a/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx b/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx index 37eb253fa06..45de4c2da15 100644 --- a/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx +++ b/frontend/providers/applaunchpad/src/pages/app/detail/components/DelModal.tsx @@ -154,7 +154,7 @@ const DelModal = ({ isLoading={loading} onClick={activePage === Page.REMINDER ? openTemplateApp : handleDelApp} > - {activePage === Page.REMINDER ? t('Confirm to go') : t('Delete')} + {activePage === Page.REMINDER ? t('confirm_to_go') : t('Delete')} From 7071e4abee8d9eb1fc7ab8aa9af5ec1e2206de35 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Thu, 15 Aug 2024 17:08:20 +0800 Subject: [PATCH 5/6] update --- frontend/providers/dbprovider/public/locales/en/common.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/providers/dbprovider/public/locales/en/common.json b/frontend/providers/dbprovider/public/locales/en/common.json index 5e01de48344..6728e837190 100644 --- a/frontend/providers/dbprovider/public/locales/en/common.json +++ b/frontend/providers/dbprovider/public/locales/en/common.json @@ -105,7 +105,7 @@ "confirm_deploy_database": "Confirm deploying the database?", "confirm_restart": "Confirm restarting this application?", "confirm_restart_pod": "Confirm restarting the pod?", - "confirm_to_go": "Confirm Navigation", + "confirm_to_go": "Confirm", "confirm_update_database": "Confirm updating the database?", "connection_info": "Connection Details", "continuous_migration": "Continuous Migration", @@ -288,4 +288,4 @@ "use_docs": "Documentation", "version": "Version", "yaml_file": "YAML" -} +} \ No newline at end of file From 9bcadf350cdb8542576e744fed15314ec65cb662 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Thu, 15 Aug 2024 17:08:33 +0800 Subject: [PATCH 6/6] update --- frontend/providers/applaunchpad/public/locales/en/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/providers/applaunchpad/public/locales/en/common.json b/frontend/providers/applaunchpad/public/locales/en/common.json index ae954091411..157cad8b535 100644 --- a/frontend/providers/applaunchpad/public/locales/en/common.json +++ b/frontend/providers/applaunchpad/public/locales/en/common.json @@ -255,7 +255,7 @@ "delete_sealaf_app_tip": "The application is deployed via cloud development. \nSimply deleting the app won't clear out all of the app's components, which may still accrue charges. \nTo completely uninstall the app and clean all related components, uninstall the entire app in cloud development.", "remind": "remind", "update_sealaf_app_tip": "This application is deployed through cloud development. To change the application, please go to cloud development.", - "confirm_to_go": "Confirm to go", + "confirm_to_go": "Confirm", "app_store": "App Store", "sealaf": "sealaf" } \ No newline at end of file