'use client' import type { FC } from 'react' import React, { useCallback, useState, } from 'react' import cn from 'classnames' import { RiArrowDownSLine, RiMenu4Line, } from '@remixicon/react' import { useTranslation } from 'react-i18next' import { useLogs } from './hooks' import NodePanel from './node' import SpecialResultPanel from './special-result-panel' import type { NodeTracing } from '@/types/workflow' import formatNodeList from '@/app/components/workflow/run/utils/format-log' type TracingPanelProps = { list: NodeTracing[] className?: string hideNodeInfo?: boolean hideNodeProcessDetail?: boolean } const TracingPanel: FC = ({ list, className, hideNodeInfo = false, hideNodeProcessDetail = false, }) => { const { t } = useTranslation() const treeNodes = formatNodeList(list, t) const [collapsedNodes, setCollapsedNodes] = useState>(new Set()) const [hoveredParallel, setHoveredParallel] = useState(null) const toggleCollapse = (id: string) => { setCollapsedNodes((prev) => { const newSet = new Set(prev) if (newSet.has(id)) newSet.delete(id) else newSet.add(id) return newSet }) } const handleParallelMouseEnter = useCallback((id: string) => { setHoveredParallel(id) }, []) const handleParallelMouseLeave = useCallback((e: React.MouseEvent) => { const relatedTarget = e.relatedTarget as Element | null if (relatedTarget && 'closest' in relatedTarget) { const closestParallel = relatedTarget.closest('[data-parallel-id]') if (closestParallel) setHoveredParallel(closestParallel.getAttribute('data-parallel-id')) else setHoveredParallel(null) } else { setHoveredParallel(null) } }, []) const { showSpecialResultPanel, showRetryDetail, setShowRetryDetailFalse, retryResultList, handleShowRetryResultList, showIteratingDetail, setShowIteratingDetailFalse, iterationResultList, iterationResultDurationMap, handleShowIterationResultList, showLoopingDetail, setShowLoopingDetailFalse, loopResultList, loopResultDurationMap, loopResultVariableMap, handleShowLoopResultList, agentOrToolLogItemStack, agentOrToolLogListMap, handleShowAgentOrToolLog, } = useLogs() const renderNode = (node: NodeTracing) => { const isParallelFirstNode = !!node.parallelDetail?.isParallelStartNode if (isParallelFirstNode) { const parallelDetail = node.parallelDetail! const isCollapsed = collapsedNodes.has(node.id) const isHovered = hoveredParallel === node.id return (
handleParallelMouseEnter(node.id)} onMouseLeave={handleParallelMouseLeave} >
{parallelDetail.parallelTitle}
{parallelDetail.children!.map(renderNode)}
) } else { const isHovered = hoveredParallel === node.id return (
{node?.parallelDetail?.branchTitle}
) } } if (showSpecialResultPanel) { return ( ) } return (
{ e.stopPropagation() e.nativeEvent.stopImmediatePropagation() }} > {treeNodes.map(renderNode)}
) } export default TracingPanel