import type { StartNodeType } from '../../nodes/start/types' import { cn } from '@langgenius/dify-ui/cn' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { RiCloseLine, RiEqualizer2Line } from '@remixicon/react' import { debounce } from 'es-toolkit/compat' import { noop } from 'es-toolkit/function' import { memo, useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useNodes } from 'reactflow' import ActionButton, { ActionButtonState } from '@/app/components/base/action-button' import { RefreshCcw01 } from '@/app/components/base/icons/src/vender/line/arrows' import { useEdgesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-edges-interactions-without-sync' import { useNodesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-nodes-interactions-without-sync' import { useStore } from '@/app/components/workflow/store' import { useWorkflowInteractions } from '../../hooks' import { useResizePanel } from '../../nodes/_base/hooks/use-resize-panel' import { useSetDebugPreviewPanelWidth } from '../../persistence/local-storage-options' import { BlockEnum } from '../../types' import ChatWrapper from './chat-wrapper' export type ChatWrapperRefType = { handleRestart: () => void } const DebugAndPreview = () => { const { t } = useTranslation() const chatRef = useRef({ handleRestart: noop }) const { handleCancelDebugAndPreviewPanel } = useWorkflowInteractions() const { handleNodeCancelRunningStatus } = useNodesInteractionsWithoutSync() const { handleEdgeCancelRunningStatus } = useEdgesInteractionsWithoutSync() const [expanded, setExpanded] = useState(true) const nodes = useNodes() const selectedNode = nodes.find((node) => node.data.selected) const startNode = nodes.find((node) => node.data.type === BlockEnum.Start) const variables = startNode?.data.variables || [] const visibleVariables = variables const [showConversationVariableModal, setShowConversationVariableModal] = useState(false) const handleRestartChat = () => { handleNodeCancelRunningStatus() handleEdgeCancelRunningStatus() chatRef.current.handleRestart() } const workflowCanvasWidth = useStore((s) => s.workflowCanvasWidth) const nodePanelWidth = useStore((s) => s.nodePanelWidth) const panelWidth = useStore((s) => s.previewPanelWidth) const setPanelWidth = useStore((s) => s.setPreviewPanelWidth) const setPanelWidthStorage = useSetDebugPreviewPanelWidth() const handleResize = useCallback( (width: number, source: 'user' | 'system' = 'user') => { if (source === 'user') setPanelWidthStorage(width) setPanelWidth(width) }, [setPanelWidth, setPanelWidthStorage], ) const maxPanelWidth = useMemo(() => { if (!workflowCanvasWidth) return 720 if (!selectedNode) return workflowCanvasWidth - 400 return workflowCanvasWidth - 400 - 400 }, [workflowCanvasWidth, selectedNode, nodePanelWidth]) const { triggerRef, containerRef } = useResizePanel({ direction: 'horizontal', triggerDirection: 'left', minWidth: 400, maxWidth: maxPanelWidth, onResize: debounce((width: number) => { handleResize(width, 'user') }), }) return (
{t(($) => $['common.debugAndPreview'], { ns: 'workflow' }).toLocaleUpperCase()}
handleRestartChat()}> } /> {t(($) => $['operation.refresh'], { ns: 'common' })} {visibleVariables.length > 0 && (
setExpanded(!expanded)} > } /> {t(($) => $['panel.userInputField'], { ns: 'workflow' })} {expanded && (
)}
)}
setShowConversationVariableModal(false)} showInputsFieldsPanel={expanded} onHide={() => setExpanded(false)} />
) } export default memo(DebugAndPreview)