import { cn } from '@langgenius/dify-ui/cn' import { ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, } from '@langgenius/dify-ui/context-menu' import { useCallback } from 'react' import { useTranslation } from 'react-i18next' import { FlowType } from '@/types/common' import { useDSL, useIsChatMode, useNodesInteractions, useWorkflowMoveMode, useWorkflowStartRun, } from './hooks' import { useHooksStore } from './hooks-store' import { TEST_RUN_MENU_HOTKEY } from './hotkeys' import { isSnippetCanvas } from './nodes/_base/hooks/snippet-input-field-vars' import AddBlock from './operator/add-block' import { useOperator } from './operator/hooks' import { ShortcutKbd } from './shortcuts/shortcut-kbd' import { useStore } from './store' import { WorkflowRunningStatus } from './types' export function PanelContextmenu({ onClose }: { onClose: () => void }) { const { t } = useTranslation() const isPanelContextMenu = useStore((s) => s.contextMenuTarget?.type === 'panel') const clipboardElements = useStore((s) => s.clipboardElements) const setShowImportDSLModal = useStore((s) => s.setShowImportDSLModal) const pendingComment = useStore((s) => s.pendingComment) const setCommentPlacing = useStore((s) => s.setCommentPlacing) const setCommentQuickAdd = useStore((s) => s.setCommentQuickAdd) const workflowRunningData = useStore((s) => s.workflowRunningData) const historyWorkflowData = useStore((s) => s.historyWorkflowData) const isRestoring = useStore((s) => s.isRestoring) const { handleNodesPaste } = useNodesInteractions() const { handleStartWorkflowRun, handleWorkflowStartRunInChatflow } = useWorkflowStartRun() const { handleAddNote } = useOperator() const { isCommentModeAvailable } = useWorkflowMoveMode() const { exportCheck } = useDSL() const accessControl = useHooksStore((s) => s.accessControl) const flowType = useHooksStore((s) => s.configsMap?.flowType) const isChatMode = useIsChatMode() const workflowOperationReadOnly = !!( workflowRunningData?.result.status === WorkflowRunningStatus.Running || workflowRunningData?.result.status === WorkflowRunningStatus.Paused || historyWorkflowData || isRestoring ) const canEditWorkflow = accessControl.canEdit && !workflowOperationReadOnly const shouldHideImportApp = flowType === FlowType.snippet || isSnippetCanvas() const renderAddBlockTrigger = useCallback(() => { return ( } className={cn( 'w-[calc(100%-8px)]', 'justify-between gap-4 border-0 bg-transparent px-3 text-left text-text-secondary', )} > {t(($) => $['common.addBlock'], { ns: 'workflow' })} ) }, [t]) const handleRunAction = useCallback(() => { if (isChatMode) handleWorkflowStartRunInChatflow() else handleStartWorkflowRun() onClose() }, [isChatMode, handleWorkflowStartRunInChatflow, handleStartWorkflowRun, onClose]) if (!isPanelContextMenu) return null return ( {canEditWorkflow && ( )} {canEditWorkflow && ( { e.stopPropagation() handleAddNote() onClose() }} > {t(($) => $['nodes.note.addNote'], { ns: 'workflow' })} )} {!workflowOperationReadOnly && isCommentModeAvailable && ( { e.stopPropagation() if (pendingComment) return setCommentQuickAdd(true) setCommentPlacing(true) onClose() }} > {t(($) => $['comments.actions.addComment'], { ns: 'workflow' })} )} {accessControl.canRun && ( {isChatMode ? t(($) => $['common.debugAndPreview'], { ns: 'workflow' }) : t(($) => $['common.run'], { ns: 'workflow' })} {!isChatMode && } )} {canEditWorkflow && ( <> { if (clipboardElements.length) { handleNodesPaste() onClose() } }} > {t(($) => $['common.pasteHere'], { ns: 'workflow' })} )} {accessControl.canImportExportDSL && ( <> exportCheck?.()} > {t(($) => $.export, { ns: 'app' })} {!shouldHideImportApp && ( setShowImportDSLModal(true)} > {t(($) => $.importApp, { ns: 'app' })} )} )} ) }