wwf
3 天以前 a430284aa21e3ae1f0d5654e55b2ad2852519cc2
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>
  )
}