diff --git a/web/app/components/app-sidebar/app-info.tsx b/web/app/components/app-sidebar/app-info.tsx
index cf55c0d68d..953ea52866 100644
--- a/web/app/components/app-sidebar/app-info.tsx
+++ b/web/app/components/app-sidebar/app-info.tsx
@@ -26,7 +26,6 @@ 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/card-view'
-import Divider from '../base/divider'
import type { Operation } from './app-operations'
import AppOperations from './app-operations'
import dynamic from 'next/dynamic'
@@ -197,7 +196,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
if (!appDetail)
return null
- const operations = [
+ const primaryOperations = [
{
id: 'edit',
title: t('app.editApp'),
@@ -224,7 +223,11 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
icon: ,
onClick: exportCheck,
},
- (appDetail.mode !== 'agent-chat' && (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow')) ? {
+ ]
+
+ const secondaryOperations: Operation[] = [
+ // Import DSL (conditional)
+ ...(appDetail.mode !== 'agent-chat' && (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow')) ? [{
id: 'import',
title: t('workflow.common.importDSL'),
icon: ,
@@ -233,18 +236,39 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
onDetailExpand?.(false)
setShowImportDSLModal(true)
},
- } : undefined,
- (appDetail.mode !== 'agent-chat' && (appDetail.mode === 'completion' || appDetail.mode === 'chat')) ? {
- id: 'switch',
- title: t('app.switch'),
- icon: ,
+ }] : [],
+ // Divider
+ {
+ id: 'divider-1',
+ title: '',
+ icon: <>>,
+ onClick: () => { /* divider has no action */ },
+ type: 'divider' as const,
+ },
+ // Delete operation
+ {
+ id: 'delete',
+ title: t('common.operation.delete'),
+ icon: ,
onClick: () => {
setOpen(false)
onDetailExpand?.(false)
- setShowSwitchModal(true)
+ setShowConfirmDelete(true)
},
- } : undefined,
- ].filter((op): op is Operation => Boolean(op))
+ },
+ ]
+
+ // Keep the switch operation separate as it's not part of the main operations
+ const switchOperation = (appDetail.mode !== 'agent-chat' && (appDetail.mode === 'completion' || appDetail.mode === 'chat')) ? {
+ id: 'switch',
+ title: t('app.switch'),
+ icon: ,
+ onClick: () => {
+ setOpen(false)
+ onDetailExpand?.(false)
+ setShowSwitchModal(true)
+ },
+ } : null
return (
@@ -322,7 +346,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
{/* operations */}
-
-
-
-
+ {/* Switch operation (if available) */}
+ {switchOperation && (
+
+
+
+ )}
{showSwitchModal && (
void
+ id: string
+ title: string
+ icon: JSX.Element
+ onClick: () => void
+ type?: 'action' | 'divider'
+ className?: string
}
-const AppOperations = ({ operations, gap }: {
- operations: Operation[]
+const AppOperations = ({ primaryOperations, secondaryOperations, gap }: {
+ primaryOperations: Operation[]
+ secondaryOperations: Operation[]
gap: number
}) => {
const { t } = useTranslation()
- const [visibleOpreations, setVisibleOperations] = useState([])
- const [moreOperations, setMoreOperations] = useState([])
const [showMore, setShowMore] = useState(false)
- const navRef = useRef(null)
const handleTriggerMore = useCallback(() => {
- setShowMore(true)
- }, [setShowMore])
+ setShowMore(prev => !prev)
+ }, [])
- useEffect(() => {
- const moreElement = document.getElementById('more')
- const navElement = document.getElementById('nav')
- let width = 0
- const containerWidth = navElement?.clientWidth ?? 0
- const moreWidth = moreElement?.clientWidth ?? 0
-
- if (containerWidth === 0 || moreWidth === 0) return
-
- const updatedEntries: Record = operations.reduce((pre, cur) => {
- pre[cur.id] = false
- return pre
- }, {} as Record)
- const childrens = Array.from(navRef.current!.children).slice(0, -1)
- for (let i = 0; i < childrens.length; i++) {
- const child: any = childrens[i]
- const id = child.dataset.targetid
- if (!id) break
- const childWidth = child.clientWidth
-
- if (width + gap + childWidth + moreWidth <= containerWidth) {
- updatedEntries[id] = true
- width += gap + childWidth
- }
- else {
- if (i === childrens.length - 1 && width + childWidth <= containerWidth)
- updatedEntries[id] = true
- else
- updatedEntries[id] = false
- break
- }
+ const renderSecondaryOperation = (operation: Operation, index: number) => {
+ if (operation.type === 'divider') {
+ return (
+
+ )
}
- setVisibleOperations(operations.filter(item => updatedEntries[item.id]))
- setMoreOperations(operations.filter(item => !updatedEntries[item.id]))
- }, [operations, gap])
+
+ return (
+
+ {cloneElement(operation.icon, {
+ className: 'h-4 w-4 text-text-tertiary',
+ })}
+
+ {operation.title}
+
+
+ )
+ }
return (
- <>
- {!visibleOpreations.length &&
- {operations.map((operation, index) =>
-
,
- )}
+
+ {/* Fixed primary operations */}
+ {primaryOperations.map(operation =>
-
}
-
- {visibleOpreations.map(operation =>
-
,
- )}
- {visibleOpreations.length < operations.length &&
,
+ )}
+
+ {/* More button - always show if there are secondary operations */}
+ {secondaryOperations.length > 0 && (
+
-
- {moreOperations.map(item =>
- {cloneElement(item.icon, { className: 'h-4 w-4 text-text-tertiary' })}
- {item.title}
-
)}
+
+ {secondaryOperations.map((operation, index) => renderSecondaryOperation(operation, index))}
- }
-
- >
+
+ )}
+
)
}