update parallel log

This commit is contained in:
Yi 2024-09-03 10:34:50 +08:00
parent 7035f64ce3
commit 83343eefe6
6 changed files with 109 additions and 43 deletions

View File

@ -312,18 +312,38 @@ export const useWorkflowRun = () => {
getNodes, getNodes,
setNodes, setNodes,
} = store.getState() } = store.getState()
if (isInIteration) { if (isInIteration) {
setWorkflowRunningData(produce(workflowRunningData!, (draft) => { setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
const tracing = draft.tracing! const tracing = draft.tracing!
const iterations = tracing[tracing.length - 1] const iterations = tracing[tracing.length - 1] // the iteration node
const currIteration = iterations.details![iterations.details!.length - 1]
const nodeInfo = currIteration[currIteration.length - 1]
currIteration[currIteration.length - 1] = { if (iterations && iterations.details) {
...nodeInfo, const iterationIndex = data.execution_metadata?.iteration_index || 0
...data, // console.log(`the current iteration index is ${iterationIndex}`)
status: NodeRunningStatus.Succeeded,
} as any // console.log(JSON.parse(JSON.stringify(iterations.details)))
if (!iterations.details[iterationIndex])
iterations.details[iterationIndex] = []
const currIteration = iterations.details[iterationIndex]
const nodeIndex = currIteration.findIndex(node =>
node.node_id === data.node_id,
)
if (nodeIndex !== -1) {
currIteration[nodeIndex] = {
...(currIteration[nodeIndex].extras ? { extras: currIteration[nodeIndex].extras } : {}),
...data,
} as any
}
else {
currIteration.push({
...data,
} as any)
}
}
})) }))
} }
else { else {
@ -332,12 +352,8 @@ export const useWorkflowRun = () => {
const currentIndex = draft.tracing!.findIndex((trace) => { const currentIndex = draft.tracing!.findIndex((trace) => {
if (!trace.execution_metadata?.parallel_id) if (!trace.execution_metadata?.parallel_id)
return trace.node_id === data.node_id return trace.node_id === data.node_id
if (trace.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id)
return trace.node_id === data.node_id && trace.execution_metadata?.parallel_start_node_id === data.execution_metadata?.parallel_start_node_id
return trace.node_id === data.node_id && trace.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id return trace.node_id === data.node_id && trace.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id
}) })
if (currentIndex > -1 && draft.tracing) { if (currentIndex > -1 && draft.tracing) {
draft.tracing[currentIndex] = { draft.tracing[currentIndex] = {
...(draft.tracing[currentIndex].extras ...(draft.tracing[currentIndex].extras
@ -347,16 +363,14 @@ export const useWorkflowRun = () => {
} as any } as any
} }
})) }))
const newNodes = produce(nodes, (draft) => { const newNodes = produce(nodes, (draft) => {
const currentNode = draft.find(node => node.id === data.node_id)! const currentNode = draft.find(node => node.id === data.node_id)!
currentNode.data._runningStatus = data.status as any currentNode.data._runningStatus = data.status as any
}) })
setNodes(newNodes) setNodes(newNodes)
prevNodeId = data.node_id prevNodeId = data.node_id
} }
if (onNodeFinished) if (onNodeFinished)
onNodeFinished(params) onNodeFinished(params)
}, },

View File

@ -385,9 +385,6 @@ export const useChat = (
const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => { const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => {
if (!item.execution_metadata?.parallel_id) if (!item.execution_metadata?.parallel_id)
return item.node_id === data.node_id return item.node_id === data.node_id
if (item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id)
return item.node_id === data.node_id && item.execution_metadata?.parallel_start_node_id === data.execution_metadata?.parallel_start_node_id
return item.node_id === data.node_id && item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id return item.node_id === data.node_id && item.execution_metadata?.parallel_id === data.execution_metadata?.parallel_id
}) })
responseItem.workflowProcess!.tracing[currentIndex] = { responseItem.workflowProcess!.tracing[currentIndex] = {

View File

@ -1,10 +1,14 @@
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React, { useCallback } from 'react' import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { RiCloseLine } from '@remixicon/react' import {
RiArrowRightSLine,
RiCloseLine,
} from '@remixicon/react'
import { ArrowNarrowLeft } from '../../base/icons/src/vender/line/arrows' import { ArrowNarrowLeft } from '../../base/icons/src/vender/line/arrows'
import TracingPanel from './tracing-panel' import TracingPanel from './tracing-panel'
import { Iteration } from '@/app/components/base/icons/src/vender/workflow'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import type { NodeTracing } from '@/types/workflow' import type { NodeTracing } from '@/types/workflow'
const i18nPrefix = 'workflow.singleRun' const i18nPrefix = 'workflow.singleRun'
@ -23,30 +27,69 @@ const IterationResultPanel: FC<Props> = ({
noWrap, noWrap,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const [expandedIterations, setExpandedIterations] = useState<Record<number, boolean>>([])
const toggleIteration = useCallback((index: number) => {
setExpandedIterations(prev => ({
...prev,
[index]: !prev[index],
}))
}, [])
const main = ( const main = (
<> <>
<div className={cn(!noWrap && 'shrink-0 ', 'pl-4 pr-3 pt-3')}> <div className={cn(!noWrap && 'shrink-0 ', 'px-4 pt-3')}>
<div className='shrink-0 flex justify-between items-center h-8'> <div className='shrink-0 flex justify-between items-center h-8'>
<div className='text-base font-semibold text-gray-900 truncate'> <div className='system-xl-semibold text-text-primary truncate'>
{t(`${i18nPrefix}.testRunIteration`)} {t(`${i18nPrefix}.testRunIteration`)}
</div> </div>
<div className='ml-2 shrink-0 p-1 cursor-pointer' onClick={onHide}> <div className='ml-2 shrink-0 p-1 cursor-pointer' onClick={onHide}>
<RiCloseLine className='w-4 h-4 text-text-tertiary ' /> <RiCloseLine className='w-4 h-4 text-text-tertiary' />
</div> </div>
</div> </div>
<div className='flex items-center py-2 space-x-1 text-text-accent cursor-pointer' onClick={onBack}> <div className='flex items-center py-2 space-x-1 text-text-accent-secondary cursor-pointer' onClick={onBack}>
<ArrowNarrowLeft className='w-4 h-4' /> <ArrowNarrowLeft className='w-4 h-4' />
<div className='leading-[18px] text-[13px] font-medium'>{t(`${i18nPrefix}.back`)}</div> <div className='system-sm-medium'>{t(`${i18nPrefix}.back`)}</div>
</div> </div>
</div> </div>
{/* List */} {/* List */}
<div className={cn(!noWrap ? 'h-0 grow' : 'max-h-full', 'overflow-y-auto px-4 pb-4 bg-gray-50')}> <div className={cn(!noWrap ? 'flex-grow overflow-auto' : 'max-h-full', 'p-2 bg-components-panel-bg')}>
{list.map((iteration, index) => ( {list.map((iteration, index) => (
<TracingPanel <div key={index} className={cn('mb-1 overflow-hidden rounded-xl bg-background-section-burn border-none')}>
list={iteration} <div
key={index} className={cn(
/> 'flex items-center justify-between w-full px-3 cursor-pointer',
expandedIterations[index] ? 'pt-3 pb-2' : 'py-3',
'rounded-xl text-left',
)}
onClick={() => toggleIteration(index)}
>
<div className={cn('flex items-center gap-2 flex-grow')}>
<div className='flex items-center justify-center w-4 h-4 rounded-[5px] border-divider-subtle bg-util-colors-cyan-cyan-500 flex-shrink-0'>
<Iteration className='w-3 h-3 text-text-primary-on-surface' />
</div>
<span className='system-sm-semibold-uppercase text-text-primary flex-grow'>
{t(`${i18nPrefix}.iteration`)} {index + 1}
</span>
<RiArrowRightSLine className={cn(
'w-4 h-4 text-text-tertiary transition-transform duration-200 flex-shrink-0',
expandedIterations[index] && 'transform rotate-90',
)} />
</div>
</div>
{expandedIterations[index] && <div
className="flex-grow h-px bg-divider-subtle"
></div>}
<div className={cn(
'overflow-hidden transition-all duration-200',
expandedIterations[index] ? 'max-h-[1000px] opacity-100' : 'max-h-0 opacity-0',
)}>
<TracingPanel
list={iteration}
className={'bg-background-section-burn'}
/>
</div>
</div>
))} ))}
</div> </div>
</> </>

View File

@ -11,8 +11,10 @@ import {
import BlockIcon from '../block-icon' import BlockIcon from '../block-icon'
import { BlockEnum } from '../types' import { BlockEnum } from '../types'
import Split from '../nodes/_base/components/split' import Split from '../nodes/_base/components/split'
import { Iteration } from '@/app/components/base/icons/src/vender/workflow'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import Button from '@/app/components/base/button'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback' import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
import type { NodeTracing } from '@/types/workflow' import type { NodeTracing } from '@/types/workflow'
@ -66,7 +68,7 @@ const NodePanel: FC<Props> = ({
}, [nodeInfo.expand, setCollapseState]) }, [nodeInfo.expand, setCollapseState])
const isIterationNode = nodeInfo.node_type === BlockEnum.Iteration const isIterationNode = nodeInfo.node_type === BlockEnum.Iteration
const handleOnShowIterationDetail = (e: React.MouseEvent<HTMLDivElement>) => { const handleOnShowIterationDetail = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation() e.stopPropagation()
e.nativeEvent.stopImmediatePropagation() e.nativeEvent.stopImmediatePropagation()
onShowIterationDetail?.(nodeInfo.details || []) onShowIterationDetail?.(nodeInfo.details || [])
@ -120,21 +122,23 @@ const NodePanel: FC<Props> = ({
{/* The nav to the iteration detail */} {/* The nav to the iteration detail */}
{isIterationNode && !notShowIterationNav && ( {isIterationNode && !notShowIterationNav && (
<div className='mt-2 mb-1 !px-2'> <div className='mt-2 mb-1 !px-2'>
<div <Button
className='flex items-center h-[34px] justify-between px-3 bg-gray-100 border-[0.5px] border-gray-200 rounded-lg cursor-pointer' className='flex items-center w-full self-stretch gap-2 px-3 py-2 bg-components-button-tertiary-bg-hover hover:bg-components-button-tertiary-bg-hover rounded-lg cursor-pointer border-none'
onClick={handleOnShowIterationDetail}> onClick={handleOnShowIterationDetail}
<div className='leading-[18px] text-[13px] font-medium text-gray-700'>{t('workflow.nodes.iteration.iteration', { count: nodeInfo.metadata?.iterator_length || nodeInfo.details?.length })}</div> >
<Iteration className='w-4 h-4 text-components-button-tertiary-text flex-shrink-0' />
<div className='flex-1 text-left system-sm-medium text-components-button-tertiary-text'>{t('workflow.nodes.iteration.iteration', { count: nodeInfo.metadata?.iterator_length || nodeInfo.details?.length })}</div>
{justShowIterationNavArrow {justShowIterationNavArrow
? ( ? (
<RiArrowRightSLine className='w-3.5 h-3.5 text-gray-500' /> <RiArrowRightSLine className='w-4 h-4 text-components-button-tertiary-text flex-shrink-0' />
) )
: ( : (
<div className='flex items-center space-x-1 text-[#155EEF]'> <div className='flex items-center space-x-1 text-[#155EEF]'>
<div className='text-[13px] font-normal '>{t('workflow.common.viewDetailInTracingPanel')}</div> <div className='text-[13px] font-normal '>{t('workflow.common.viewDetailInTracingPanel')}</div>
<RiArrowRightSLine className='w-3.5 h-3.5' /> <RiArrowRightSLine className='w-4 h-4 text-components-button-tertiary-text flex-shrink-0' />
</div> </div>
)} )}
</div> </Button>
<Split className='mt-2' /> <Split className='mt-2' />
</div> </div>
)} )}

View File

@ -20,6 +20,7 @@ import type { NodeTracing } from '@/types/workflow'
type TracingPanelProps = { type TracingPanelProps = {
list: NodeTracing[] list: NodeTracing[]
onShowIterationDetail?: (detail: NodeTracing[][]) => void onShowIterationDetail?: (detail: NodeTracing[][]) => void
className?: string
} }
type TracingNodeProps = { type TracingNodeProps = {
@ -44,7 +45,7 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
levelCounts[levelKey]++ levelCounts[levelKey]++
const parentTitle = parentId ? parallelStacks[parentId].parallelTitle : '' const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : ''
const levelNumber = parentTitle ? parseInt(parentTitle.split('-')[1]) + 1 : 1 const levelNumber = parentTitle ? parseInt(parentTitle.split('-')[1]) + 1 : 1
const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : '' const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : ''
return `PARALLEL-${levelNumber}${letter}` return `PARALLEL-${levelNumber}${letter}`
@ -52,7 +53,7 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
const getBranchTitle = (parentId: string | null, branchNum: number): string => { const getBranchTitle = (parentId: string | null, branchNum: number): string => {
const levelKey = parentId || 'root' const levelKey = parentId || 'root'
const parentTitle = parentId ? parallelStacks[parentId].parallelTitle : '' const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : ''
const levelNumber = parentTitle ? parseInt(parentTitle.split('-')[1]) + 1 : 1 const levelNumber = parentTitle ? parseInt(parentTitle.split('-')[1]) + 1 : 1
const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : '' const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : ''
const branchLetter = String.fromCharCode(64 + branchNum) const branchLetter = String.fromCharCode(64 + branchNum)
@ -126,9 +127,12 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
}) })
} }
else { else {
const sameBranchIndex = parallelStacks[parallel_id].children.findLastIndex(c => let sameBranchIndex = parallelStacks[parallel_id].children.findLastIndex(c =>
c.data?.execution_metadata.parallel_start_node_id === parallel_start_node_id, c.data?.execution_metadata.parallel_start_node_id === parallel_start_node_id,
) )
if (parallelStacks[parallel_id].children[sameBranchIndex + 1]?.isParallel)
sameBranchIndex++
parallelStacks[parallel_id].children.splice(sameBranchIndex + 1, 0, { parallelStacks[parallel_id].children.splice(sameBranchIndex + 1, 0, {
id: node.id, id: node.id,
isParallel: false, isParallel: false,
@ -143,7 +147,7 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
return rootNodes return rootNodes
} }
const TracingPanel: FC<TracingPanelProps> = ({ list, onShowIterationDetail }) => { const TracingPanel: FC<TracingPanelProps> = ({ list, onShowIterationDetail, className }) => {
const treeNodes = buildLogTree(list) const treeNodes = buildLogTree(list)
const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(new Set()) const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(new Set())
const [hoveredParallel, setHoveredParallel] = useState<string | null>(null) const [hoveredParallel, setHoveredParallel] = useState<string | null>(null)
@ -238,7 +242,7 @@ const TracingPanel: FC<TracingPanelProps> = ({ list, onShowIterationDetail }) =>
} }
return ( return (
<div className='bg-components-panel-bg py-2'> <div className={cn(className || 'bg-components-panel-bg', 'py-2')}>
{treeNodes.map(renderNode)} {treeNodes.map(renderNode)}
</div> </div>
) )

View File

@ -145,6 +145,8 @@ export type NodeFinishedResponse = {
total_price: number total_price: number
currency: string currency: string
parallel_id?: string parallel_id?: string
parallel_start_node_id?: string
iteration_index?: number
} }
created_at: number created_at: number
} }
@ -159,6 +161,8 @@ export type IterationStartedResponse = {
node_id: string node_id: string
metadata: { metadata: {
iterator_length: number iterator_length: number
iteration_id: string
iteration_index: number
} }
created_at: number created_at: number
extras?: any extras?: any