From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/app-sidebar/app-info.tsx | 522 ++++++++++++++++++++++++++++++++------------------------- 1 files changed, 289 insertions(+), 233 deletions(-) diff --git a/app/components/app-sidebar/app-info.tsx b/app/components/app-sidebar/app-info.tsx index 5ec0e31..12f9c59 100644 --- a/app/components/app-sidebar/app-info.tsx +++ b/app/components/app-sidebar/app-info.tsx @@ -1,20 +1,18 @@ import { useTranslation } from 'react-i18next' import { useRouter } from 'next/navigation' import { useContext, useContextSelector } from 'use-context-selector' +import { RiArrowDownSLine } from '@remixicon/react' import React, { useCallback, useState } from 'react' -import { - RiDeleteBinLine, - RiEditLine, - RiEqualizer2Line, - RiExchange2Line, - RiFileCopy2Line, - RiFileDownloadLine, - RiFileUploadLine, - RiMoreLine, -} from '@remixicon/react' import AppIcon from '../base/app-icon' import SwitchAppModal from '../app/switch-app-modal' +import s from './style.module.css' import cn from '@/utils/classnames' +import { + PortalToFollowElem, + PortalToFollowElemContent, + PortalToFollowElemTrigger, +} from '@/app/components/base/portal-to-follow-elem' +import Divider from '@/app/components/base/divider' import Confirm from '@/app/components/base/confirm' import { useStore as useAppStore } from '@/app/components/app/store' import { ToastContext } from '@/app/components/base/toast' @@ -24,6 +22,8 @@ import DuplicateAppModal from '@/app/components/app/duplicate-modal' import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' import CreateAppModal from '@/app/components/explore/create-app-modal' +import { AiText, ChatBot, CuteRobot } from '@/app/components/base/icons/src/vender/solid/communication' +import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel' import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { getRedirection } from '@/utils/app-redirection' @@ -31,10 +31,6 @@ import type { EnvironmentVariable } from '@/app/components/workflow/types' import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal' import { fetchWorkflowDraft } from '@/service/workflow' -import ContentDialog from '@/app/components/base/content-dialog' -import Button from '@/app/components/base/button' -import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView' -import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../base/portal-to-follow-elem' export type IAppInfoProps = { expand: boolean @@ -51,6 +47,7 @@ const [showEditModal, setShowEditModal] = useState(false) const [showDuplicateModal, setShowDuplicateModal] = useState(false) const [showConfirmDelete, setShowConfirmDelete] = useState(false) + const [showSwitchTip, setShowSwitchTip] = useState<string>('') const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false) const [showImportDSLModal, setShowImportDSLModal] = useState<boolean>(false) const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([]) @@ -88,7 +85,7 @@ setAppDetail(app) mutateApps() } - catch { + catch (e) { notify({ type: 'error', message: t('app.editFailed') }) } }, [appDetail, mutateApps, notify, setAppDetail, t]) @@ -115,7 +112,7 @@ onPlanInfoChanged() getRedirection(true, newApp, replace) } - catch { + catch (e) { notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) } } @@ -134,7 +131,7 @@ a.download = `${appDetail.name}.yml` a.click() } - catch { + catch (e) { notify({ type: 'error', message: t('app.exportFailed') }) } } @@ -155,7 +152,7 @@ } setSecretEnvList(list) } - catch { + catch (e) { notify({ type: 'error', message: t('app.exportFailed') }) } } @@ -178,240 +175,299 @@ }) } setShowConfirmDelete(false) - }, [appDetail, mutateApps, notify, onPlanInfoChanged, replace, setAppDetail, t]) + }, [appDetail, mutateApps, notify, onPlanInfoChanged, replace, t]) const { isCurrentWorkspaceEditor } = useAppContext() - - const [showMore, setShowMore] = useState(false) - const handleTriggerMore = useCallback(() => { - setShowMore(true) - }, [setShowMore]) if (!appDetail) return null return ( - <div> - <button - onClick={() => { - if (isCurrentWorkspaceEditor) - setOpen(v => !v) - }} - className='block w-full' - > - <div className={cn('flex rounded-lg', expand ? 'flex-col gap-2 p-2 pb-2.5' : 'items-start justify-center gap-1 p-1', open && 'bg-state-base-hover', isCurrentWorkspaceEditor && 'cursor-pointer hover:bg-state-base-hover')}> - <div className={`flex items-center self-stretch ${expand ? 'justify-between' : 'flex-col gap-1'}`}> - <AppIcon - size={expand ? 'large' : 'small'} - iconType={appDetail.icon_type} - icon={appDetail.icon} - background={appDetail.icon_background} - imageUrl={appDetail.icon_url} - /> - <div className='flex items-center justify-center rounded-md p-0.5'> - <div className='flex h-5 w-5 items-center justify-center'> - <RiEqualizer2Line className='h-4 w-4 text-text-tertiary' /> - </div> + <PortalToFollowElem + open={open} + onOpenChange={setOpen} + placement='bottom-start' + offset={4} + > + <div className='relative'> + <PortalToFollowElemTrigger + onClick={() => { + if (isCurrentWorkspaceEditor) + setOpen(v => !v) + }} + className='block' + > + <div className={cn('flex p-1 rounded-lg', open && 'bg-gray-100', isCurrentWorkspaceEditor && 'hover:bg-gray-100 cursor-pointer')}> + <div className='relative shrink-0 mr-2'> + <AppIcon + size={expand ? 'large' : 'small'} + iconType={appDetail.icon_type} + icon={appDetail.icon} + background={appDetail.icon_background} + imageUrl={appDetail.icon_url} + /> + <span className={cn( + 'absolute bottom-[-3px] right-[-3px] w-4 h-4 p-0.5 bg-white rounded border-[0.5px] border-[rgba(0,0,0,0.02)] shadow-sm', + !expand && '!w-3.5 !h-3.5 !bottom-[-2px] !right-[-2px]', + )}> + {appDetail.mode === 'advanced-chat' && ( + <ChatBot className={cn('w-3 h-3 text-[#1570EF]', !expand && '!w-2.5 !h-2.5')} /> + )} + {appDetail.mode === 'agent-chat' && ( + <CuteRobot className={cn('w-3 h-3 text-indigo-600', !expand && '!w-2.5 !h-2.5')} /> + )} + {appDetail.mode === 'chat' && ( + <ChatBot className={cn('w-3 h-3 text-[#1570EF]', !expand && '!w-2.5 !h-2.5')} /> + )} + {appDetail.mode === 'completion' && ( + <AiText className={cn('w-3 h-3 text-[#0E9384]', !expand && '!w-2.5 !h-2.5')} /> + )} + {appDetail.mode === 'workflow' && ( + <Route className={cn('w-3 h-3 text-[#f79009]', !expand && '!w-2.5 !h-2.5')} /> + )} + </span> </div> - </div> - { - expand && ( - <div className='flex flex-col items-start gap-1'> - <div className='flex w-full'> - <div className='system-md-semibold truncate text-text-secondary'>{appDetail.name}</div> + {expand && ( + <div className="grow w-0"> + <div className='flex justify-between items-center text-sm leading-5 font-medium text-text-secondary'> + <div className='truncate' title={appDetail.name}>{appDetail.name}</div> + {isCurrentWorkspaceEditor && <RiArrowDownSLine className='shrink-0 ml-[2px] w-3 h-3 text-gray-500' />} </div> - <div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div> + <div className='flex items-center text-[10px] leading-[18px] font-medium text-gray-500 gap-1'> + {appDetail.mode === 'advanced-chat' && ( + <> + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div> + <div title={t('app.types.advanced') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.advanced').toUpperCase()}</div> + </> + )} + {appDetail.mode === 'agent-chat' && ( + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.agent').toUpperCase()}</div> + )} + {appDetail.mode === 'chat' && ( + <> + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div> + <div title={t('app.types.basic') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{(t('app.types.basic').toUpperCase())}</div> + </> + )} + {appDetail.mode === 'completion' && ( + <> + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.completion').toUpperCase()}</div> + <div title={t('app.types.basic') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{(t('app.types.basic').toUpperCase())}</div> + </> + )} + {appDetail.mode === 'workflow' && ( + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.workflow').toUpperCase()}</div> + )} + </div> </div> - ) - } - </div> - </button> - <ContentDialog - show={open} - onClose={() => setOpen(false)} - className='absolute bottom-2 left-2 top-2 flex w-[420px] flex-col rounded-2xl !p-0' - > - <div className='flex shrink-0 flex-col items-start justify-center gap-3 self-stretch p-4'> - <div className='flex items-center gap-3 self-stretch'> - <AppIcon - size="large" - iconType={appDetail.icon_type} - icon={appDetail.icon} - background={appDetail.icon_background} - imageUrl={appDetail.icon_url} - /> - <div className='flex w-full grow flex-col items-start justify-center'> - <div className='system-md-semibold w-full truncate text-text-secondary'>{appDetail.name}</div> - <div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div> - </div> + )} </div> - {/* description */} - {appDetail.description && ( - <div className='system-xs-regular text-text-tertiary'>{appDetail.description}</div> - )} - {/* operations */} - <div className='flex flex-wrap items-center gap-1 self-stretch'> - <Button - size={'small'} - variant={'secondary'} - className='gap-[1px]' - onClick={() => { + </PortalToFollowElemTrigger> + <PortalToFollowElemContent className='z-[1002]'> + <div className='relative w-[320px] bg-white rounded-2xl shadow-xl'> + {/* header */} + <div className={cn('flex pl-4 pt-3 pr-3', !appDetail.description && 'pb-2')}> + <div className='relative shrink-0 mr-2'> + <AppIcon + size="large" + iconType={appDetail.icon_type} + icon={appDetail.icon} + background={appDetail.icon_background} + imageUrl={appDetail.icon_url} + /> + <span className='absolute bottom-[-3px] right-[-3px] w-4 h-4 p-0.5 bg-white rounded border-[0.5px] border-[rgba(0,0,0,0.02)] shadow-sm'> + {appDetail.mode === 'advanced-chat' && ( + <ChatBot className='w-3 h-3 text-[#1570EF]' /> + )} + {appDetail.mode === 'agent-chat' && ( + <CuteRobot className='w-3 h-3 text-indigo-600' /> + )} + {appDetail.mode === 'chat' && ( + <ChatBot className='w-3 h-3 text-[#1570EF]' /> + )} + {appDetail.mode === 'completion' && ( + <AiText className='w-3 h-3 text-[#0E9384]' /> + )} + {appDetail.mode === 'workflow' && ( + <Route className='w-3 h-3 text-[#f79009]' /> + )} + </span> + </div> + <div className='grow w-0'> + <div title={appDetail.name} className='flex justify-between items-center text-sm leading-5 font-medium text-gray-900 truncate'>{appDetail.name}</div> + <div className='flex items-center text-[10px] leading-[18px] font-medium text-gray-500 gap-1'> + {appDetail.mode === 'advanced-chat' && ( + <> + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div> + <div title={t('app.types.advanced') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.advanced').toUpperCase()}</div> + </> + )} + {appDetail.mode === 'agent-chat' && ( + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.agent').toUpperCase()}</div> + )} + {appDetail.mode === 'chat' && ( + <> + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.chatbot').toUpperCase()}</div> + <div title={t('app.types.basic') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{(t('app.types.basic').toUpperCase())}</div> + </> + )} + {appDetail.mode === 'completion' && ( + <> + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.completion').toUpperCase()}</div> + <div title={t('app.types.basic') || ''} className='px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{(t('app.types.basic').toUpperCase())}</div> + </> + )} + {appDetail.mode === 'workflow' && ( + <div className='shrink-0 px-1 border bg-white border-[rgba(0,0,0,0.08)] rounded-[5px] truncate'>{t('app.types.workflow').toUpperCase()}</div> + )} + </div> + </div> + </div> + {/* description */} + {appDetail.description && ( + <div className='px-4 py-2 text-gray-500 text-xs leading-[18px]'>{appDetail.description}</div> + )} + {/* operations */} + <Divider className="!my-1" /> + <div className="w-full py-1"> + <div className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onClick={() => { setOpen(false) setShowEditModal(true) - }} - > - <RiEditLine className='h-3.5 w-3.5 text-components-button-secondary-text' /> - <span className='system-xs-medium text-components-button-secondary-text'>{t('app.editApp')}</span> - </Button> - <Button - size={'small'} - variant={'secondary'} - className='gap-[1px]' - onClick={() => { + }}> + <span className='text-gray-700 text-sm leading-5'>{t('app.editApp')}</span> + </div> + <div className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onClick={() => { setOpen(false) setShowDuplicateModal(true) - }} - > - <RiFileCopy2Line className='h-3.5 w-3.5 text-components-button-secondary-text' /> - <span className='system-xs-medium text-components-button-secondary-text'>{t('app.duplicate')}</span> - </Button> - <Button - size={'small'} - variant={'secondary'} - className='gap-[1px]' - onClick={exportCheck} - > - <RiFileDownloadLine className='h-3.5 w-3.5 text-components-button-secondary-text' /> - <span className='system-xs-medium text-components-button-secondary-text'>{t('app.export')}</span> - </Button> - {appDetail.mode !== 'agent-chat' && <PortalToFollowElem - open={showMore} - onOpenChange={setShowMore} - placement='bottom-end' - offset={{ - mainAxis: 4, }}> - <PortalToFollowElemTrigger onClick={handleTriggerMore}> - <Button - size={'small'} - variant={'secondary'} - className='gap-[1px]' - > - <RiMoreLine className='h-3.5 w-3.5 text-components-button-secondary-text' /> - <span className='system-xs-medium text-components-button-secondary-text'>{t('common.operation.more')}</span> - </Button> - </PortalToFollowElemTrigger> - <PortalToFollowElemContent className='z-[21]'> - <div className='flex w-[264px] flex-col rounded-[12px] border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'> - { - (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') - && <div className='flex h-8 cursor-pointer items-center gap-x-1 rounded-lg p-1.5 hover:bg-state-base-hover' - onClick={() => { - setOpen(false) - setShowImportDSLModal(true) - }}> - <RiFileUploadLine className='h-4 w-4 text-text-tertiary' /> - <span className='system-md-regular text-text-secondary'>{t('workflow.common.importDSL')}</span> - </div> - } - { - (appDetail.mode === 'completion' || appDetail.mode === 'chat') - && <div className='flex h-8 cursor-pointer items-center gap-x-1 rounded-lg p-1.5 hover:bg-state-base-hover' - onClick={() => { - setOpen(false) - setShowSwitchModal(true) - }}> - <RiExchange2Line className='h-4 w-4 text-text-tertiary' /> - <span className='system-md-regular text-text-secondary'>{t('app.switch')}</span> - </div> - } + <span className='text-gray-700 text-sm leading-5'>{t('app.duplicate')}</span> + </div> + {(appDetail.mode === 'completion' || appDetail.mode === 'chat') && ( + <> + <Divider className="!my-1" /> + <div + 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={() => { + setOpen(false) + setShowSwitchModal(true) + }} + > + <span className='text-gray-700 text-sm leading-5'>{t('app.switch')}</span> + </div> + </> + )} + <Divider className="!my-1" /> + <div className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' onClick={exportCheck}> + <span className='text-gray-700 text-sm leading-5'>{t('app.export')}</span> + </div> + { + (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') && ( + <div + className='h-9 py-2 px-3 mx-1 flex items-center hover:bg-gray-50 rounded-lg cursor-pointer' + onClick={() => { + setOpen(false) + setShowImportDSLModal(true) + }}> + <span className='text-gray-700 text-sm leading-5'>{t('workflow.common.importDSL')}</span> + </div> + ) + } + <Divider className="!my-1" /> + <div className='group h-9 py-2 px-3 mx-1 flex items-center hover:bg-red-50 rounded-lg cursor-pointer' onClick={() => { + setOpen(false) + setShowConfirmDelete(true) + }}> + <span className='text-gray-700 text-sm leading-5 group-hover:text-red-500'> + {t('common.operation.delete')} + </span> + </div> + </div> + {/* switch tip */} + <div + className={cn( + 'hidden absolute left-[324px] top-0 w-[376px] rounded-xl bg-white border-[0.5px] border-[rgba(0,0,0,0.05)] shadow-lg', + showSwitchTip && '!block', + )} + > + <div className={cn( + 'w-full h-[256px] bg-center bg-no-repeat bg-contain rounded-xl', + showSwitchTip === 'chat' && s.expertPic, + showSwitchTip === 'completion' && s.completionPic, + )} /> + <div className='px-4 pb-2'> + <div className='flex items-center gap-1 text-gray-700 text-md leading-6 font-semibold'> + {showSwitchTip === 'chat' ? t('app.types.advanced') : t('app.types.workflow')} + <span className='px-1 rounded-[5px] bg-white border border-black/8 text-gray-500 text-[10px] leading-[18px] font-medium'>BETA</span> </div> - </PortalToFollowElemContent> - </PortalToFollowElem>} + <div className='text-orange-500 text-xs leading-[18px] font-medium'>{t('app.newApp.advancedFor').toLocaleUpperCase()}</div> + <div className='mt-1 text-gray-500 text-sm leading-5'>{t('app.newApp.advancedDescription')}</div> + </div> + </div> </div> - </div> - <div className='flex flex-1'> - <CardView - appId={appDetail.id} - isInPanel={true} - className='flex grow flex-col gap-2 overflow-auto px-2 py-1' + </PortalToFollowElemContent> + {showSwitchModal && ( + <SwitchAppModal + inAppDetail + show={showSwitchModal} + appDetail={appDetail} + onClose={() => setShowSwitchModal(false)} + onSuccess={() => setShowSwitchModal(false)} /> - </div> - <div className='flex min-h-fit shrink-0 flex-col items-start justify-center gap-3 self-stretch border-t-[0.5px] border-divider-subtle p-2'> - <Button - size={'medium'} - variant={'ghost'} - className='gap-0.5' - onClick={() => { - setOpen(false) - setShowConfirmDelete(true) - }} - > - <RiDeleteBinLine className='h-4 w-4 text-text-tertiary' /> - <span className='system-sm-medium text-text-tertiary'>{t('common.operation.deleteApp')}</span> - </Button> - </div> - </ContentDialog> - {showSwitchModal && ( - <SwitchAppModal - inAppDetail - show={showSwitchModal} - appDetail={appDetail} - onClose={() => setShowSwitchModal(false)} - onSuccess={() => setShowSwitchModal(false)} - /> - )} - {showEditModal && ( - <CreateAppModal - isEditModal - appName={appDetail.name} - appIconType={appDetail.icon_type} - appIcon={appDetail.icon} - appIconBackground={appDetail.icon_background} - appIconUrl={appDetail.icon_url} - appDescription={appDetail.description} - appMode={appDetail.mode} - appUseIconAsAnswerIcon={appDetail.use_icon_as_answer_icon} - show={showEditModal} - onConfirm={onEdit} - onHide={() => setShowEditModal(false)} - /> - )} - {showDuplicateModal && ( - <DuplicateAppModal - appName={appDetail.name} - icon_type={appDetail.icon_type} - icon={appDetail.icon} - icon_background={appDetail.icon_background} - icon_url={appDetail.icon_url} - show={showDuplicateModal} - onConfirm={onCopy} - onHide={() => setShowDuplicateModal(false)} - /> - )} - {showConfirmDelete && ( - <Confirm - title={t('app.deleteAppConfirmTitle')} - content={t('app.deleteAppConfirmContent')} - isShow={showConfirmDelete} - onConfirm={onConfirmDelete} - onCancel={() => setShowConfirmDelete(false)} - /> - )} - {showImportDSLModal && ( - <UpdateDSLModal - onCancel={() => setShowImportDSLModal(false)} - onBackup={exportCheck} - /> - )} - {secretEnvList.length > 0 && ( - <DSLExportConfirmModal - envList={secretEnvList} - onConfirm={onExport} - onClose={() => setSecretEnvList([])} - /> - )} - </div> + )} + {showEditModal && ( + <CreateAppModal + isEditModal + appName={appDetail.name} + appIconType={appDetail.icon_type} + appIcon={appDetail.icon} + appIconBackground={appDetail.icon_background} + appIconUrl={appDetail.icon_url} + appDescription={appDetail.description} + appMode={appDetail.mode} + appUseIconAsAnswerIcon={appDetail.use_icon_as_answer_icon} + show={showEditModal} + onConfirm={onEdit} + onHide={() => setShowEditModal(false)} + /> + )} + {showDuplicateModal && ( + <DuplicateAppModal + appName={appDetail.name} + icon_type={appDetail.icon_type} + icon={appDetail.icon} + icon_background={appDetail.icon_background} + icon_url={appDetail.icon_url} + show={showDuplicateModal} + onConfirm={onCopy} + onHide={() => setShowDuplicateModal(false)} + /> + )} + {showConfirmDelete && ( + <Confirm + title={t('app.deleteAppConfirmTitle')} + content={t('app.deleteAppConfirmContent')} + isShow={showConfirmDelete} + onConfirm={onConfirmDelete} + onCancel={() => setShowConfirmDelete(false)} + /> + )} + {showImportDSLModal && ( + <UpdateDSLModal + onCancel={() => setShowImportDSLModal(false)} + onBackup={exportCheck} + /> + )} + {secretEnvList.length > 0 && ( + <DSLExportConfirmModal + envList={secretEnvList} + onConfirm={onExport} + onClose={() => setSecretEnvList([])} + /> + )} + </div> + </PortalToFollowElem> ) } -- Gitblit v1.8.0