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