mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-15 22:05:53 +08:00
update parallel log
This commit is contained in:
parent
7035f64ce3
commit
83343eefe6
@ -312,18 +312,38 @@ export const useWorkflowRun = () => {
|
||||
getNodes,
|
||||
setNodes,
|
||||
} = store.getState()
|
||||
|
||||
if (isInIteration) {
|
||||
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
|
||||
const tracing = draft.tracing!
|
||||
const iterations = tracing[tracing.length - 1]
|
||||
const currIteration = iterations.details![iterations.details!.length - 1]
|
||||
const nodeInfo = currIteration[currIteration.length - 1]
|
||||
const iterations = tracing[tracing.length - 1] // the iteration node
|
||||
|
||||
currIteration[currIteration.length - 1] = {
|
||||
...nodeInfo,
|
||||
if (iterations && iterations.details) {
|
||||
const iterationIndex = data.execution_metadata?.iteration_index || 0
|
||||
// console.log(`the current iteration index is ${iterationIndex}`)
|
||||
|
||||
// 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,
|
||||
status: NodeRunningStatus.Succeeded,
|
||||
} as any
|
||||
}
|
||||
else {
|
||||
currIteration.push({
|
||||
...data,
|
||||
} as any)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
else {
|
||||
@ -332,12 +352,8 @@ export const useWorkflowRun = () => {
|
||||
const currentIndex = draft.tracing!.findIndex((trace) => {
|
||||
if (!trace.execution_metadata?.parallel_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
|
||||
})
|
||||
|
||||
if (currentIndex > -1 && draft.tracing) {
|
||||
draft.tracing[currentIndex] = {
|
||||
...(draft.tracing[currentIndex].extras
|
||||
@ -347,16 +363,14 @@ export const useWorkflowRun = () => {
|
||||
} as any
|
||||
}
|
||||
}))
|
||||
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
const currentNode = draft.find(node => node.id === data.node_id)!
|
||||
|
||||
currentNode.data._runningStatus = data.status as any
|
||||
})
|
||||
setNodes(newNodes)
|
||||
|
||||
prevNodeId = data.node_id
|
||||
}
|
||||
|
||||
if (onNodeFinished)
|
||||
onNodeFinished(params)
|
||||
},
|
||||
|
@ -385,9 +385,6 @@ export const useChat = (
|
||||
const currentIndex = responseItem.workflowProcess!.tracing!.findIndex((item) => {
|
||||
if (!item.execution_metadata?.parallel_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
|
||||
})
|
||||
responseItem.workflowProcess!.tracing[currentIndex] = {
|
||||
|
@ -1,10 +1,14 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback } from 'react'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
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 TracingPanel from './tracing-panel'
|
||||
import { Iteration } from '@/app/components/base/icons/src/vender/workflow'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
const i18nPrefix = 'workflow.singleRun'
|
||||
@ -23,30 +27,69 @@ const IterationResultPanel: FC<Props> = ({
|
||||
noWrap,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [expandedIterations, setExpandedIterations] = useState<Record<number, boolean>>([])
|
||||
|
||||
const toggleIteration = useCallback((index: number) => {
|
||||
setExpandedIterations(prev => ({
|
||||
...prev,
|
||||
[index]: !prev[index],
|
||||
}))
|
||||
}, [])
|
||||
|
||||
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='text-base font-semibold text-gray-900 truncate'>
|
||||
<div className='system-xl-semibold text-text-primary truncate'>
|
||||
{t(`${i18nPrefix}.testRunIteration`)}
|
||||
</div>
|
||||
<div className='ml-2 shrink-0 p-1 cursor-pointer' onClick={onHide}>
|
||||
<RiCloseLine className='w-4 h-4 text-text-tertiary' />
|
||||
</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' />
|
||||
<div className='leading-[18px] text-[13px] font-medium'>{t(`${i18nPrefix}.back`)}</div>
|
||||
<div className='system-sm-medium'>{t(`${i18nPrefix}.back`)}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 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) => (
|
||||
<div key={index} className={cn('mb-1 overflow-hidden rounded-xl bg-background-section-burn border-none')}>
|
||||
<div
|
||||
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}
|
||||
key={index}
|
||||
className={'bg-background-section-burn'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
|
@ -11,8 +11,10 @@ import {
|
||||
import BlockIcon from '../block-icon'
|
||||
import { BlockEnum } from '../types'
|
||||
import Split from '../nodes/_base/components/split'
|
||||
import { Iteration } from '@/app/components/base/icons/src/vender/workflow'
|
||||
import cn from '@/utils/classnames'
|
||||
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 { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
@ -66,7 +68,7 @@ const NodePanel: FC<Props> = ({
|
||||
}, [nodeInfo.expand, setCollapseState])
|
||||
|
||||
const isIterationNode = nodeInfo.node_type === BlockEnum.Iteration
|
||||
const handleOnShowIterationDetail = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const handleOnShowIterationDetail = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
onShowIterationDetail?.(nodeInfo.details || [])
|
||||
@ -120,21 +122,23 @@ const NodePanel: FC<Props> = ({
|
||||
{/* The nav to the iteration detail */}
|
||||
{isIterationNode && !notShowIterationNav && (
|
||||
<div className='mt-2 mb-1 !px-2'>
|
||||
<div
|
||||
className='flex items-center h-[34px] justify-between px-3 bg-gray-100 border-[0.5px] border-gray-200 rounded-lg cursor-pointer'
|
||||
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>
|
||||
<Button
|
||||
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}
|
||||
>
|
||||
<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
|
||||
? (
|
||||
<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='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>
|
||||
</Button>
|
||||
<Split className='mt-2' />
|
||||
</div>
|
||||
)}
|
||||
|
@ -20,6 +20,7 @@ import type { NodeTracing } from '@/types/workflow'
|
||||
type TracingPanelProps = {
|
||||
list: NodeTracing[]
|
||||
onShowIterationDetail?: (detail: NodeTracing[][]) => void
|
||||
className?: string
|
||||
}
|
||||
|
||||
type TracingNodeProps = {
|
||||
@ -44,7 +45,7 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
|
||||
|
||||
levelCounts[levelKey]++
|
||||
|
||||
const parentTitle = parentId ? parallelStacks[parentId].parallelTitle : ''
|
||||
const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : ''
|
||||
const levelNumber = parentTitle ? parseInt(parentTitle.split('-')[1]) + 1 : 1
|
||||
const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : ''
|
||||
return `PARALLEL-${levelNumber}${letter}`
|
||||
@ -52,7 +53,7 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
|
||||
|
||||
const getBranchTitle = (parentId: string | null, branchNum: number): string => {
|
||||
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 letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : ''
|
||||
const branchLetter = String.fromCharCode(64 + branchNum)
|
||||
@ -126,9 +127,12 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
|
||||
})
|
||||
}
|
||||
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,
|
||||
)
|
||||
if (parallelStacks[parallel_id].children[sameBranchIndex + 1]?.isParallel)
|
||||
sameBranchIndex++
|
||||
|
||||
parallelStacks[parallel_id].children.splice(sameBranchIndex + 1, 0, {
|
||||
id: node.id,
|
||||
isParallel: false,
|
||||
@ -143,7 +147,7 @@ function buildLogTree(nodes: NodeTracing[]): TracingNodeProps[] {
|
||||
return rootNodes
|
||||
}
|
||||
|
||||
const TracingPanel: FC<TracingPanelProps> = ({ list, onShowIterationDetail }) => {
|
||||
const TracingPanel: FC<TracingPanelProps> = ({ list, onShowIterationDetail, className }) => {
|
||||
const treeNodes = buildLogTree(list)
|
||||
const [collapsedNodes, setCollapsedNodes] = useState<Set<string>>(new Set())
|
||||
const [hoveredParallel, setHoveredParallel] = useState<string | null>(null)
|
||||
@ -238,7 +242,7 @@ const TracingPanel: FC<TracingPanelProps> = ({ list, onShowIterationDetail }) =>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='bg-components-panel-bg py-2'>
|
||||
<div className={cn(className || 'bg-components-panel-bg', 'py-2')}>
|
||||
{treeNodes.map(renderNode)}
|
||||
</div>
|
||||
)
|
||||
|
@ -145,6 +145,8 @@ export type NodeFinishedResponse = {
|
||||
total_price: number
|
||||
currency: string
|
||||
parallel_id?: string
|
||||
parallel_start_node_id?: string
|
||||
iteration_index?: number
|
||||
}
|
||||
created_at: number
|
||||
}
|
||||
@ -159,6 +161,8 @@ export type IterationStartedResponse = {
|
||||
node_id: string
|
||||
metadata: {
|
||||
iterator_length: number
|
||||
iteration_id: string
|
||||
iteration_index: number
|
||||
}
|
||||
created_at: number
|
||||
extras?: any
|
||||
|
Loading…
x
Reference in New Issue
Block a user