From 7362b9dc03e2ff4eb0b8520cec13ec44a1d8ece2 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Thu, 14 Aug 2025 17:47:09 +0100 Subject: [PATCH] simplify log tree structure (#6389) * fix(frontend): fix bad log tree build * remove entry structure to use modules as input for log tree * clean * fix typo --------- Co-authored-by: Ruben Fiszel --- frontend/src/lib/components/FlowLogUtils.ts | 11 - .../src/lib/components/FlowLogViewer.svelte | 257 +++++++++++------- .../components/FlowLogViewerWrapper.svelte | 156 +---------- 3 files changed, 161 insertions(+), 263 deletions(-) delete mode 100644 frontend/src/lib/components/FlowLogUtils.ts diff --git a/frontend/src/lib/components/FlowLogUtils.ts b/frontend/src/lib/components/FlowLogUtils.ts deleted file mode 100644 index f95d255977..0000000000 --- a/frontend/src/lib/components/FlowLogUtils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { FlowModuleValue } from '$lib/gen' - -export interface FlowLogEntry { - id: string - stepId: string - stepNumber?: number - summary?: string - stepType?: FlowModuleValue['type'] - subflows?: FlowLogEntry[][] - subflowsSummary?: string[] -} diff --git a/frontend/src/lib/components/FlowLogViewer.svelte b/frontend/src/lib/components/FlowLogViewer.svelte index a6d5949275..369578ff17 100644 --- a/frontend/src/lib/components/FlowLogViewer.svelte +++ b/frontend/src/lib/components/FlowLogViewer.svelte @@ -16,18 +16,17 @@ import ObjectViewer from './propertyPicker/ObjectViewer.svelte' import LogViewer from './LogViewer.svelte' import FlowLogViewer from './FlowLogViewer.svelte' - import type { FlowModuleValue, FlowStatusModule, Job } from '$lib/gen' + import type { FlowModule, FlowModuleValue, FlowStatusModule, Job } from '$lib/gen' import { twMerge } from 'tailwind-merge' import FlowJobsMenu from './flows/map/FlowJobsMenu.svelte' import BarsStaggered from './icons/BarsStaggered.svelte' import type { GraphModuleState } from './graph/model' import type { Writable } from 'svelte/store' - import type { FlowLogEntry } from './FlowLogUtils' type RootJobData = Partial interface Props { - logEntries: FlowLogEntry[] + modules: FlowModule[] localModuleStates: Writable> rootJob: RootJobData flowStatus: FlowStatusModule['type'] | undefined @@ -50,7 +49,7 @@ } let { - logEntries, + modules, localModuleStates, rootJob, flowStatus, @@ -133,28 +132,47 @@ } // Find all parents of error steps - function findParentsOfErrors(entries: FlowLogEntry[]): Set { + function findParentsOfErrors(modules: FlowModule[]): Set { const parentsWithErrors = new Set() - function traverseEntries(entryList: FlowLogEntry[], parentId?: string) { + function traverseModules(modules: FlowModule[], parentId?: string) { let hasChildError = false - for (const entry of entryList) { + for (const module of modules) { let currentEntryHasError = false // Check if this entry has subflows with errors - if (entry.subflows && entry.subflows.length > 0) { - for (const subflow of entry.subflows) { - const subflowHasError = traverseEntries(subflow, entry.stepId) + if ( + module.value.type === 'forloopflow' || + (module.value.type === 'whileloopflow' && module.value.modules.length > 0) + ) { + const subflowHasError = traverseModules(module.value.modules, module.id) + if (subflowHasError) { + currentEntryHasError = true + parentsWithErrors.add(module.id) + } + } else if (module.value.type === 'branchone' || module.value.type === 'branchall') { + if (module.value.branches.length > 0) { + for (const branch of module.value.branches) { + const subflowHasError = traverseModules(branch.modules, module.id) + if (subflowHasError) { + currentEntryHasError = true + parentsWithErrors.add(module.id) + } + } + } + if (module.value.type === 'branchone' && module.value.default.length > 0) { + // Also check default branch + const subflowHasError = traverseModules(module.value.default, module.id) if (subflowHasError) { currentEntryHasError = true - parentsWithErrors.add(entry.stepId) + parentsWithErrors.add(module.id) } } } // Check if this entry itself has an error (but don't flag it - only its parents) - const stepStatus = $localModuleStates[entry.stepId]?.type + const stepStatus = $localModuleStates[module.id]?.type if (stepStatus === 'Failure') { currentEntryHasError = true // Don't add the entry itself to parentsWithErrors @@ -170,13 +188,13 @@ return hasChildError } - traverseEntries(entries, flowId) + traverseModules(modules, flowId) return parentsWithErrors } // Get flow info for display const flowInfo = $derived.by(() => { - const parentsWithErrors = findParentsOfErrors(logEntries) + const parentsWithErrors = findParentsOfErrors(modules) return { jobId: rootJob.id, inputs: rootJob.args || {}, @@ -188,6 +206,47 @@ parentsWithErrors } }) + + function hasSubflows(module: FlowModule) { + return ( + module.value.type === 'forloopflow' || + module.value.type === 'whileloopflow' || + module.value.type === 'branchall' || + module.value.type === 'branchone' + ) + } + + function getSubflows(module: FlowModule) { + const subflows: Array<{ modules: FlowModule[]; label: string; flowId: string }> = [] + + if (module.value.type === 'forloopflow' || module.value.type === 'whileloopflow') { + subflows.push({ + modules: module.value.modules, + label: module.summary || '', + flowId: `${module.id}-subflow` + }) + } else if (module.value.type === 'branchall' || module.value.type === 'branchone') { + // Add all branches + for (let i = 0; i < module.value.branches.length; i++) { + const branch = module.value.branches[i] + subflows.push({ + modules: branch.modules, + label: branch.summary || `branch ${i + 1}`, + flowId: `${module.id}-subflow-${i}` + }) + } + // Add default branch for branchone + if (module.value.type === 'branchone') { + subflows.push({ + modules: module.value.default, + label: 'default', + flowId: `${module.id}-subflow-default` + }) + } + } + + return subflows + } {#if render} @@ -242,7 +301,7 @@
{/if} -
+
{getStepProgress(rootJob, logEntries.length)} + {getStepProgress(rootJob, modules.length)}
@@ -340,25 +399,21 @@ {/if} - {#if logEntries.length > 0} - {#each logEntries as entry (entry.id)} - {@const isLeafStep = - entry.stepType !== 'branchall' && - entry.stepType !== 'branchone' && - entry.stepType !== 'forloopflow' && - entry.stepType !== 'whileloopflow'} - {@const status = $localModuleStates[entry.stepId]?.type} + {#if modules.length > 0} + {#each modules as module (module.id)} + {@const isLeafStep = !hasSubflows(module)} + {@const status = $localModuleStates[module.id]?.type} {@const isRunning = status === 'InProgress' || status === 'WaitingForExecutor'} - {@const hasEmptySubflowValue = hasEmptySubflow(entry.stepId, entry.stepType)} + {@const hasEmptySubflowValue = hasEmptySubflow(module.id, module.value.type)} {@const isCollapsible = !hasEmptySubflowValue}
  • {#if isCollapsible}