| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							|  |  |  | import { useRouter } from 'next/navigation' | 
					
						
							|  |  |  | import { useContext, useContextSelector } from 'use-context-selector' | 
					
						
							|  |  |  | import React, { useCallback, useState } from 'react' | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   RiDeleteBinLine, | 
					
						
							|  |  |  |   RiEditLine, | 
					
						
							|  |  |  |   RiEqualizer2Line, | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |   RiExchange2Line, | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |   RiFileCopy2Line, | 
					
						
							|  |  |  |   RiFileDownloadLine, | 
					
						
							|  |  |  |   RiFileUploadLine, | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |   RiMoreLine, | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  | } from '@remixicon/react' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import AppIcon from '../base/app-icon' | 
					
						
							|  |  |  | import SwitchAppModal from '../app/switch-app-modal' | 
					
						
							| 
									
										
										
										
											2024-07-09 15:05:40 +08:00
										 |  |  | import cn from '@/utils/classnames' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import Confirm from '@/app/components/base/confirm' | 
					
						
							|  |  |  | import { useStore as useAppStore } from '@/app/components/app/store' | 
					
						
							|  |  |  | import { ToastContext } from '@/app/components/base/toast' | 
					
						
							| 
									
										
										
										
											2024-06-17 03:06:32 -05:00
										 |  |  | import AppsContext, { useAppContext } from '@/context/app-context' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import { useProviderContext } from '@/context/provider-context' | 
					
						
							|  |  |  | import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' | 
					
						
							|  |  |  | 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 type { CreateAppModalProps } from '@/app/components/explore/create-app-modal' | 
					
						
							|  |  |  | import { NEED_REFRESH_APP_LIST_KEY } from '@/config' | 
					
						
							|  |  |  | import { getRedirection } from '@/utils/app-redirection' | 
					
						
							| 
									
										
										
										
											2024-06-25 15:46:12 +08:00
										 |  |  | import UpdateDSLModal from '@/app/components/workflow/update-dsl-modal' | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  | import type { EnvironmentVariable } from '@/app/components/workflow/types' | 
					
						
							|  |  |  | import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal' | 
					
						
							|  |  |  | import { fetchWorkflowDraft } from '@/service/workflow' | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  | 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' | 
					
						
							| 
									
										
										
										
											2025-05-20 12:07:50 +08:00
										 |  |  | import Divider from '../base/divider' | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  | import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../base/portal-to-follow-elem' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export type IAppInfoProps = { | 
					
						
							|  |  |  |   expand: boolean | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |   onlyShowDetail?: boolean | 
					
						
							|  |  |  |   openState?: boolean | 
					
						
							|  |  |  |   onDetailExpand?: (expand: boolean) => void | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  | const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailExpand }: IAppInfoProps) => { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  |   const { notify } = useContext(ToastContext) | 
					
						
							|  |  |  |   const { replace } = useRouter() | 
					
						
							|  |  |  |   const { onPlanInfoChanged } = useProviderContext() | 
					
						
							|  |  |  |   const appDetail = useAppStore(state => state.appDetail) | 
					
						
							|  |  |  |   const setAppDetail = useAppStore(state => state.setAppDetail) | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |   const [open, setOpen] = useState(openState) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const [showEditModal, setShowEditModal] = useState(false) | 
					
						
							|  |  |  |   const [showDuplicateModal, setShowDuplicateModal] = useState(false) | 
					
						
							|  |  |  |   const [showConfirmDelete, setShowConfirmDelete] = useState(false) | 
					
						
							|  |  |  |   const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false) | 
					
						
							| 
									
										
										
										
											2024-06-25 15:46:12 +08:00
										 |  |  |   const [showImportDSLModal, setShowImportDSLModal] = useState<boolean>(false) | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  |   const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const mutateApps = useContextSelector( | 
					
						
							|  |  |  |     AppsContext, | 
					
						
							|  |  |  |     state => state.mutateApps, | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({ | 
					
						
							|  |  |  |     name, | 
					
						
							| 
									
										
										
										
											2024-08-19 09:16:33 +08:00
										 |  |  |     icon_type, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     icon, | 
					
						
							|  |  |  |     icon_background, | 
					
						
							|  |  |  |     description, | 
					
						
							| 
									
										
										
										
											2024-09-02 21:00:41 +09:00
										 |  |  |     use_icon_as_answer_icon, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   }) => { | 
					
						
							|  |  |  |     if (!appDetail) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       const app = await updateAppInfo({ | 
					
						
							|  |  |  |         appID: appDetail.id, | 
					
						
							|  |  |  |         name, | 
					
						
							| 
									
										
										
										
											2024-08-19 09:16:33 +08:00
										 |  |  |         icon_type, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |         icon, | 
					
						
							|  |  |  |         icon_background, | 
					
						
							|  |  |  |         description, | 
					
						
							| 
									
										
										
										
											2024-09-02 21:00:41 +09:00
										 |  |  |         use_icon_as_answer_icon, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       }) | 
					
						
							|  |  |  |       setShowEditModal(false) | 
					
						
							|  |  |  |       notify({ | 
					
						
							|  |  |  |         type: 'success', | 
					
						
							|  |  |  |         message: t('app.editDone'), | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       setAppDetail(app) | 
					
						
							|  |  |  |       mutateApps() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-04-14 11:27:14 +08:00
										 |  |  |     catch { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       notify({ type: 'error', message: t('app.editFailed') }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, [appDetail, mutateApps, notify, setAppDetail, t]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-19 09:16:33 +08:00
										 |  |  |   const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     if (!appDetail) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       const newApp = await copyApp({ | 
					
						
							|  |  |  |         appID: appDetail.id, | 
					
						
							|  |  |  |         name, | 
					
						
							| 
									
										
										
										
											2024-08-19 09:16:33 +08:00
										 |  |  |         icon_type, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |         icon, | 
					
						
							|  |  |  |         icon_background, | 
					
						
							|  |  |  |         mode: appDetail.mode, | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       setShowDuplicateModal(false) | 
					
						
							|  |  |  |       notify({ | 
					
						
							|  |  |  |         type: 'success', | 
					
						
							|  |  |  |         message: t('app.newApp.appCreated'), | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | 
					
						
							|  |  |  |       mutateApps() | 
					
						
							|  |  |  |       onPlanInfoChanged() | 
					
						
							|  |  |  |       getRedirection(true, newApp, replace) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-04-14 11:27:14 +08:00
										 |  |  |     catch { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  |   const onExport = async (include = false) => { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     if (!appDetail) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  |       const { data } = await exportAppConfig({ | 
					
						
							|  |  |  |         appID: appDetail.id, | 
					
						
							|  |  |  |         include, | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       const a = document.createElement('a') | 
					
						
							|  |  |  |       const file = new Blob([data], { type: 'application/yaml' }) | 
					
						
							|  |  |  |       a.href = URL.createObjectURL(file) | 
					
						
							|  |  |  |       a.download = `${appDetail.name}.yml` | 
					
						
							|  |  |  |       a.click() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-04-14 11:27:14 +08:00
										 |  |  |     catch { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       notify({ type: 'error', message: t('app.exportFailed') }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  |   const exportCheck = async () => { | 
					
						
							|  |  |  |     if (!appDetail) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     if (appDetail.mode !== 'workflow' && appDetail.mode !== 'advanced-chat') { | 
					
						
							|  |  |  |       onExport() | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       const workflowDraft = await fetchWorkflowDraft(`/apps/${appDetail.id}/workflows/draft`) | 
					
						
							|  |  |  |       const list = (workflowDraft.environment_variables || []).filter(env => env.value_type === 'secret') | 
					
						
							|  |  |  |       if (list.length === 0) { | 
					
						
							|  |  |  |         onExport() | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       setSecretEnvList(list) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-04-14 11:27:14 +08:00
										 |  |  |     catch { | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  |       notify({ type: 'error', message: t('app.exportFailed') }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const onConfirmDelete = useCallback(async () => { | 
					
						
							|  |  |  |     if (!appDetail) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       await deleteApp(appDetail.id) | 
					
						
							|  |  |  |       notify({ type: 'success', message: t('app.appDeleted') }) | 
					
						
							|  |  |  |       mutateApps() | 
					
						
							|  |  |  |       onPlanInfoChanged() | 
					
						
							|  |  |  |       setAppDetail() | 
					
						
							|  |  |  |       replace('/apps') | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     catch (e: any) { | 
					
						
							|  |  |  |       notify({ | 
					
						
							|  |  |  |         type: 'error', | 
					
						
							|  |  |  |         message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`, | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     setShowConfirmDelete(false) | 
					
						
							| 
									
										
										
										
											2025-04-14 11:27:14 +08:00
										 |  |  |   }, [appDetail, mutateApps, notify, onPlanInfoChanged, replace, setAppDetail, t]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-17 03:06:32 -05:00
										 |  |  |   const { isCurrentWorkspaceEditor } = useAppContext() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |   const [showMore, setShowMore] = useState(false) | 
					
						
							|  |  |  |   const handleTriggerMore = useCallback(() => { | 
					
						
							|  |  |  |     setShowMore(true) | 
					
						
							|  |  |  |   }, [setShowMore]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   if (!appDetail) | 
					
						
							|  |  |  |     return null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |     <div> | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |       {!onlyShowDetail && ( | 
					
						
							|  |  |  |         <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> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |               </div> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |             </div> | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |             { | 
					
						
							|  |  |  |               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> | 
					
						
							|  |  |  |                   </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> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 </div> | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |               ) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           </div> | 
					
						
							|  |  |  |         </button> | 
					
						
							|  |  |  |       )} | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |       <ContentDialog | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |         show={onlyShowDetail ? openState : open} | 
					
						
							|  |  |  |         onClose={() => { | 
					
						
							|  |  |  |           setOpen(false) | 
					
						
							|  |  |  |           onDetailExpand?.(false) | 
					
						
							|  |  |  |         }} | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         className='absolute bottom-2 left-2 top-2 flex w-[420px] flex-col rounded-2xl !p-0' | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |       > | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         <div className='flex shrink-0 flex-col items-start justify-center gap-3 self-stretch p-4'> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |           <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} | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             <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> | 
					
						
							| 
									
										
										
										
											2025-03-24 10:17:04 +08:00
										 |  |  |               <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> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |             </div> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |           </div> | 
					
						
							|  |  |  |           {/* description */} | 
					
						
							|  |  |  |           {appDetail.description && ( | 
					
						
							| 
									
										
										
										
											2025-06-25 16:41:55 +08:00
										 |  |  |             <div className='system-xs-regular overflow-wrap-anywhere max-h-[105px] w-full max-w-full overflow-y-auto whitespace-normal break-words text-text-tertiary'>{appDetail.description}</div> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |           )} | 
					
						
							|  |  |  |           {/* operations */} | 
					
						
							| 
									
										
										
										
											2025-03-24 15:54:00 +08:00
										 |  |  |           <div className='flex flex-wrap items-center gap-1 self-stretch'> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |             <Button | 
					
						
							|  |  |  |               size={'small'} | 
					
						
							|  |  |  |               variant={'secondary'} | 
					
						
							|  |  |  |               className='gap-[1px]' | 
					
						
							|  |  |  |               onClick={() => { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 setOpen(false) | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |                 onDetailExpand?.(false) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 setShowEditModal(true) | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |               }} | 
					
						
							|  |  |  |             > | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |               <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> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |             </Button> | 
					
						
							|  |  |  |             <Button | 
					
						
							|  |  |  |               size={'small'} | 
					
						
							|  |  |  |               variant={'secondary'} | 
					
						
							|  |  |  |               className='gap-[1px]' | 
					
						
							|  |  |  |               onClick={() => { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 setOpen(false) | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |                 onDetailExpand?.(false) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |                 setShowDuplicateModal(true) | 
					
						
							| 
									
										
										
										
											2025-05-20 12:07:50 +08:00
										 |  |  |               }}> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |               <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> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |             </Button> | 
					
						
							|  |  |  |             <Button | 
					
						
							|  |  |  |               size={'small'} | 
					
						
							|  |  |  |               variant={'secondary'} | 
					
						
							|  |  |  |               className='gap-[1px]' | 
					
						
							|  |  |  |               onClick={exportCheck} | 
					
						
							|  |  |  |             > | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |               <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> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |             </Button> | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |             {appDetail.mode !== 'agent-chat' && <PortalToFollowElem | 
					
						
							|  |  |  |               open={showMore} | 
					
						
							|  |  |  |               onOpenChange={setShowMore} | 
					
						
							|  |  |  |               placement='bottom-end' | 
					
						
							|  |  |  |               offset={{ | 
					
						
							|  |  |  |                 mainAxis: 4, | 
					
						
							|  |  |  |               }}> | 
					
						
							|  |  |  |               <PortalToFollowElemTrigger onClick={handleTriggerMore}> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |                 <Button | 
					
						
							|  |  |  |                   size={'small'} | 
					
						
							|  |  |  |                   variant={'secondary'} | 
					
						
							|  |  |  |                   className='gap-[1px]' | 
					
						
							|  |  |  |                 > | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |                   <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> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |                 </Button> | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |               </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) | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |                         onDetailExpand?.(false) | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |                         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) | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |                         onDetailExpand?.(false) | 
					
						
							| 
									
										
										
										
											2025-05-07 14:58:45 +08:00
										 |  |  |                         setShowSwitchModal(true) | 
					
						
							|  |  |  |                       }}> | 
					
						
							|  |  |  |                       <RiExchange2Line className='h-4 w-4 text-text-tertiary' /> | 
					
						
							|  |  |  |                       <span className='system-md-regular text-text-secondary'>{t('app.switch')}</span> | 
					
						
							|  |  |  |                     </div> | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 </div> | 
					
						
							|  |  |  |               </PortalToFollowElemContent> | 
					
						
							|  |  |  |             </PortalToFollowElem>} | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |         </div> | 
					
						
							|  |  |  |         <div className='flex flex-1'> | 
					
						
							|  |  |  |           <CardView | 
					
						
							|  |  |  |             appId={appDetail.id} | 
					
						
							|  |  |  |             isInPanel={true} | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             className='flex grow flex-col gap-2 overflow-auto px-2 py-1' | 
					
						
							| 
									
										
										
										
											2024-07-22 15:29:39 +08:00
										 |  |  |           /> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |         </div> | 
					
						
							| 
									
										
										
										
											2025-05-20 12:07:50 +08:00
										 |  |  |         <Divider /> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         <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'> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |           <Button | 
					
						
							|  |  |  |             size={'medium'} | 
					
						
							|  |  |  |             variant={'ghost'} | 
					
						
							|  |  |  |             className='gap-0.5' | 
					
						
							|  |  |  |             onClick={() => { | 
					
						
							|  |  |  |               setOpen(false) | 
					
						
							| 
									
										
										
										
											2025-06-24 09:10:30 +08:00
										 |  |  |               onDetailExpand?.(false) | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |               setShowConfirmDelete(true) | 
					
						
							|  |  |  |             }} | 
					
						
							|  |  |  |           > | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             <RiDeleteBinLine className='h-4 w-4 text-text-tertiary' /> | 
					
						
							|  |  |  |             <span className='system-sm-medium text-text-tertiary'>{t('common.operation.deleteApp')}</span> | 
					
						
							| 
									
										
										
										
											2025-02-07 18:56:43 +08:00
										 |  |  |           </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> | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   ) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default React.memo(AppInfo) |