| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 | 
							- '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<TracingPanelProps> = ({
 -   list,
 -   className,
 -   hideNodeInfo = false,
 -   hideNodeProcessDetail = false,
 - }) => {
 -   const { t } = useTranslation()
 -   const treeNodes = formatNodeList(list, t)
 -   const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(() => new Set())
 -   const [hoveredParallel, setHoveredParallel] = useState<string | null>(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 (
 -         <div
 -           key={node.id}
 -           className="relative mb-2 ml-4"
 -           data-parallel-id={node.id}
 -           onMouseEnter={() => handleParallelMouseEnter(node.id)}
 -           onMouseLeave={handleParallelMouseLeave}
 -         >
 -           <div className="mb-1 flex items-center">
 -             <button
 -               onClick={() => toggleCollapse(node.id)}
 -               className={cn(
 -                 'mr-2 transition-colors',
 -                 isHovered ? 'rounded border-components-button-primary-border bg-components-button-primary-bg text-text-primary-on-surface' : 'text-text-secondary hover:text-text-primary',
 -               )}
 -             >
 -               {isHovered ? <RiArrowDownSLine className="h-3 w-3" /> : <RiMenu4Line className="h-3 w-3 text-text-tertiary" />}
 -             </button>
 -             <div className="system-xs-semibold-uppercase flex items-center text-text-secondary">
 -               <span>{parallelDetail.parallelTitle}</span>
 -             </div>
 -             <div
 -               className="mx-2 h-px grow bg-divider-subtle"
 -               style={{ background: 'linear-gradient(to right, rgba(16, 24, 40, 0.08), rgba(255, 255, 255, 0)' }}
 -             ></div>
 -           </div>
 -           <div className={`relative pl-2 ${isCollapsed ? 'hidden' : ''}`}>
 -             <div className={cn(
 -               'absolute bottom-0 left-[5px] top-0 w-[2px]',
 -               isHovered ? 'bg-text-accent-secondary' : 'bg-divider-subtle',
 -             )}></div>
 -             {parallelDetail.children!.map(renderNode)}
 -           </div>
 -         </div>
 -       )
 -     }
 -     else {
 -       const isHovered = hoveredParallel === node.id
 -       return (
 -         <div key={node.id}>
 -           <div className={cn('system-2xs-medium-uppercase -mb-1.5 pl-4', isHovered ? 'text-text-tertiary' : 'text-text-quaternary')}>
 -             {node?.parallelDetail?.branchTitle}
 -           </div>
 -           <NodePanel
 -             nodeInfo={node!}
 -             allExecutions={list}
 -             onShowIterationDetail={handleShowIterationResultList}
 -             onShowLoopDetail={handleShowLoopResultList}
 -             onShowRetryDetail={handleShowRetryResultList}
 -             onShowAgentOrToolLog={handleShowAgentOrToolLog}
 -             hideInfo={hideNodeInfo}
 -             hideProcessDetail={hideNodeProcessDetail}
 -           />
 -         </div>
 -       )
 -     }
 -   }
 - 
 -   if (showSpecialResultPanel) {
 -     return (
 -       <SpecialResultPanel
 -         showRetryDetail={showRetryDetail}
 -         setShowRetryDetailFalse={setShowRetryDetailFalse}
 -         retryResultList={retryResultList}
 - 
 -         showIteratingDetail={showIteratingDetail}
 -         setShowIteratingDetailFalse={setShowIteratingDetailFalse}
 -         iterationResultList={iterationResultList}
 -         iterationResultDurationMap={iterationResultDurationMap}
 - 
 -         showLoopingDetail={showLoopingDetail}
 -         setShowLoopingDetailFalse={setShowLoopingDetailFalse}
 -         loopResultList={loopResultList}
 -         loopResultDurationMap={loopResultDurationMap}
 -         loopResultVariableMap={loopResultVariableMap}
 - 
 -         agentOrToolLogItemStack={agentOrToolLogItemStack}
 -         agentOrToolLogListMap={agentOrToolLogListMap}
 -         handleShowAgentOrToolLog={handleShowAgentOrToolLog}
 -       />
 -     )
 -   }
 - 
 -   return (
 -     <div
 -       className={cn('py-2', className)}
 -       onClick={(e) => {
 -         e.stopPropagation()
 -         e.nativeEvent.stopImmediatePropagation()
 -       }}
 -     >
 -       {treeNodes.map(renderNode)}
 -     </div>
 -   )
 - }
 - 
 - export default TracingPanel
 
 
  |