mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-16 06:05:58 +08:00
update parallel log
This commit is contained in:
parent
7035f64ce3
commit
83343eefe6
@ -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
|
||||||
|
// 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,
|
...data,
|
||||||
status: NodeRunningStatus.Succeeded,
|
|
||||||
} as any
|
} 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)
|
||||||
},
|
},
|
||||||
|
@ -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] = {
|
||||||
|
@ -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) => (
|
||||||
|
<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
|
<TracingPanel
|
||||||
list={iteration}
|
list={iteration}
|
||||||
key={index}
|
className={'bg-background-section-burn'}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user