diff --git a/web/app/components/app-sidebar/app-info.tsx b/web/app/components/app-sidebar/app-info.tsx index 314429f317..4b8adcce21 100644 --- a/web/app/components/app-sidebar/app-info.tsx +++ b/web/app/components/app-sidebar/app-info.tsx @@ -4,6 +4,7 @@ import { useContext, useContextSelector } from 'use-context-selector' import cn from 'classnames' import React, { useCallback, useState } from 'react' import AppIcon from '../base/app-icon' +import SwitchAppModal from '../app/switch-app-modal' import s from './style.module.css' import { PortalToFollowElem, @@ -41,6 +42,7 @@ const AppInfo = ({ expand }: IAppInfoProps) => { const [showDuplicateModal, setShowDuplicateModal] = useState(false) const [showConfirmDelete, setShowConfirmDelete] = useState(false) const [showSwitchTip, setShowSwitchTip] = useState('') + const [showSwitchModal, setShowSwitchModal] = useState(true) const mutateApps = useContextSelector( AppsContext, @@ -262,7 +264,10 @@ const AppInfo = ({ expand }: IAppInfoProps) => { className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onMouseEnter={() => setShowSwitchTip(appDetail.mode)} onMouseLeave={() => setShowSwitchTip('')} - onClick={() => setShowSwitchTip(appDetail.mode)} + onClick={() => { + setOpen(false) + setShowSwitchModal(true) + }} > {t('app.switch')} @@ -298,6 +303,14 @@ const AppInfo = ({ expand }: IAppInfoProps) => { + {showSwitchModal && ( + setShowSwitchModal(false)} + onSuccess={() => setShowSwitchModal(false)} + /> + )} {showEditModal && ( void + onClose: () => void +} + +const SwitchAppModal = ({ show, appDetail, onSuccess, onClose }: SwitchAppModalProps) => { + const { push } = useRouter() + const { t } = useTranslation() + const { notify } = useContext(ToastContext) + + const { isCurrentWorkspaceManager } = useAppContext() + const { plan, enableBilling } = useProviderContext() + const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps) + + const [emoji, setEmoji] = useState({ icon: appDetail.icon, icon_background: appDetail.icon_background }) + const [showEmojiPicker, setShowEmojiPicker] = useState(false) + const [name, setName] = useState(`${appDetail.name}(copy)`) + const [removeOriginal, setRemoveOriginal] = useState(false) + + const goStart = async () => { + // ###TODO### SWITCH + try { + const app = await importApp({ + data: '', + }) + if (onSuccess) + onSuccess() + if (onClose) + onClose() + notify({ type: 'success', message: t('app.newApp.appCreated') }) + localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') + getRedirection(isCurrentWorkspaceManager, app, push) + } + catch (e) { + notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) + } + } + + return ( + {}} + > +
+ +
+
+ +
+
{t('app.switch')}
+
+ {t('app.switchTipStart')} + {t('app.switchTip')} + {t('app.switchTipEnd')} +
+
+
{t('app.switchLabel')}
+
+ { setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} /> + setName(e.target.value)} + placeholder={t('app.newApp.appNamePlaceholder') || ''} + className='grow h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg border border-transparent outline-none appearance-none caret-primary-600 placeholder:text-gray-400 hover:bg-gray-50 hover:border hover:border-gray-300 focus:bg-gray-50 focus:border focus:border-gray-300 focus:shadow-xs' + /> +
+ {showEmojiPicker && { + setEmoji({ icon, icon_background }) + setShowEmojiPicker(false) + }} + onClose={() => { + setEmoji({ icon: appDetail.icon, icon_background: appDetail.icon_background }) + setShowEmojiPicker(false) + }} + />} +
+ {isAppsFull && } +
+
+ setRemoveOriginal(!removeOriginal)} className="w-4 h-4 rounded border-gray-300 text-blue-700 cursor-pointer focus:ring-blue-700" /> + +
+
+ + +
+
+
+ ) +} + +export default SwitchAppModal diff --git a/web/app/components/app/switch-app-modal/style.module.css b/web/app/components/app/switch-app-modal/style.module.css new file mode 100644 index 0000000000..14367ec575 --- /dev/null +++ b/web/app/components/app/switch-app-modal/style.module.css @@ -0,0 +1,3 @@ +.bg { + background: linear-gradient(180deg, rgba(247, 144, 9, 0.05) 0%, rgba(247, 144, 9, 0.00) 24.41%), #F9FAFB; +} diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 3bcd636457..28de91ce11 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -67,6 +67,12 @@ const translation = { cancel: 'Cancel', }, switch: 'Switch to Workflow Orchestrate', + switchTipStart: 'A new app copy will be created for you, and the new copy will switch to Workflow Orchestrate. The new copy will ', + switchTip: 'not allow', + switchTipEnd: ' switching back to Basic Orchestrate.', + switchLabel: 'The app copy to be created', + removeOriginal: 'Delete the original app', + switchStart: 'Start swtich', } export default translation diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index 3946c99730..5dcd498619 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -66,6 +66,12 @@ const translation = { cancel: '取消', }, switch: '迁移为工作流编排', + switchTipStart: '将为您创建一个使用工作流编排的新应用。新应用将', + switchTip: '不能够', + switchTipEnd: '迁移回基础编排', + switchLabel: '新应用创建为', + removeOriginal: '删除原应用', + switchStart: '开始迁移', } export default translation