fix: improve performance of flow viewer

This commit is contained in:
Ruben Fiszel
2025-09-27 08:48:01 +00:00
parent 7020dfd5e7
commit 3ad50eef9d
5 changed files with 132 additions and 94 deletions
@@ -67,7 +67,7 @@
let selectedJobStep: string | undefined = $state(undefined)
let isRunning: boolean = $state(false)
let jobProgressReset: (() => void) | undefined = $state(undefined)
let progressBar: FlowProgressBar | undefined = $state(undefined)
export function test() {
runPreview(previewArgs, undefined)
@@ -80,7 +80,7 @@
args: Record<string, any>,
restartedFrom: RestartedFrom | undefined
) {
jobProgressReset?.()
progressBar?.reset()
const newFlow = { value: { modules }, summary: '' }
jobId = await runFlowPreview(args, newFlow, $pathStore, restartedFrom)
isRunning = true
@@ -161,7 +161,7 @@
<div></div>
</div>
<div class="w-full flex flex-col gap-y-1">
<FlowProgressBar {job} bind:reset={jobProgressReset} />
<FlowProgressBar {job} bind:this={progressBar} />
</div>
<div class="overflow-y-auto grow pr-4">
<div class="max-h-1/2 overflow-auto border-b">
@@ -88,7 +88,7 @@
retryStatus.val = {}
suspendStatus.val = {}
globalRefreshes = {}
flowState.val = {}
flowState = {}
localDurationStatuses = {}
localModuleStates = {}
}
@@ -2,18 +2,27 @@
import { type Job } from '$lib/gen'
import ProgressBar from '../progressBar/ProgressBar.svelte'
export let job: Job | undefined = undefined
export let currentSubJobProgress: number | undefined = undefined
interface Props {
job?: Job | undefined
currentSubJobProgress?: number | undefined
class?: string
}
let error: number | undefined = undefined
let index = 0
let subIndex: number | undefined = undefined
let subLength: number | undefined = undefined
let length = 1
let nextInProgress = false
let subIndexIsPercent: boolean = false
let {
job = undefined,
currentSubJobProgress = $bindable(undefined),
class: className
}: Props = $props()
$: if (job) updateJobProgress(job)
let error: number | undefined = $state(undefined)
let index = $state(0)
let subIndex: number | undefined = $state(undefined)
let subLength: number | undefined = $state(undefined)
let length = $state(1)
let nextInProgress = $state(false)
let subIndexIsPercent: boolean = $state(false)
let progressBar = $state<ProgressBar | undefined>(undefined)
function updateJobProgress(job: Job) {
const modules = job?.flow_status?.modules
@@ -40,8 +49,8 @@
newError = maxDone
maxDone = maxDone + 1
}
}
subIndexIsPercent = false;
}
subIndexIsPercent = false
// Loop is still iterating
if (module?.iterator) {
@@ -54,12 +63,12 @@
} else if (module?.branchall) {
subStepIndex = module.branchall.branch
subStepLength = module.branchall.len
} else if (module?.progress) {
} else if (module?.progress) {
const clamp = (num, min, max) => Math.min(Math.max(num, min), max)
subStepIndex = clamp(module?.progress, subIndex ?? 0, 99)
// Jitter protection >^^^^^^^^
subStepLength = 100
subIndexIsPercent = true;
subIndexIsPercent = true
currentSubJobProgress = subStepIndex
} else {
currentSubJobProgress = undefined
@@ -73,26 +82,27 @@
nextInProgress = newNextInProgress
}
let resetP: any
export function reset() {
resetP?.()
progressBar?.resetP()
error = undefined
subIndex = undefined
subLength = undefined
length = 1
index = 0
}
$effect(() => {
job && updateJobProgress(job)
})
</script>
<ProgressBar
bind:resetP
bind:this={progressBar}
{length}
{index}
{nextInProgress}
{subLength}
{subIndex}
{error}
bind:subIndexIsPercent
class={$$props.class}
{subIndexIsPercent}
class={className}
/>
@@ -4,28 +4,43 @@
import type { Writable } from 'svelte/store'
import { twMerge } from 'tailwind-merge'
export let sourceX: number
export let sourceY: number
export let sourcePosition: Position
export let targetX: number
export let targetY: number
export let targetPosition: Position
export let markerEnd: string | undefined = undefined
export let data: { class?: string } = {}
interface Props {
sourceX: number
sourceY: number
sourcePosition: Position
targetX: number
targetY: number
targetPosition: Position
markerEnd?: string | undefined
data?: { class?: string }
}
const { useDataflow } = getContext<{
useDataflow: Writable<boolean | undefined>
}>('FlowGraphContext')
$: [edgePath] = getBezierPath({
let {
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: 0.25
})
markerEnd = undefined,
data = {}
}: Props = $props()
const { useDataflow } = getContext<{
useDataflow: Writable<boolean | undefined>
}>('FlowGraphContext')
let [edgePath] = $derived(
getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: 0.25
})
)
</script>
<BaseEdge
@@ -1,77 +1,88 @@
<script lang="ts">
import { tweened } from 'svelte/motion'
import { Tween } from 'svelte/motion'
import { linear } from 'svelte/easing'
import { twMerge } from 'tailwind-merge'
function getTween(initialValue = 0, duration = 200) {
return tweened(initialValue, {
duration,
easing: linear
})
// Remove padding/margin, border radius and titles
interface Props {
error?: number | undefined
index: number
subIndex: number | undefined
subLength: number | undefined
nextInProgress?: boolean
// Used for displaying progress of subjob of flow
subIndexIsPercent?: boolean
// Used in individual job test runs
compact?: boolean
// Removes `Step 1` and replaces it with `Running`
hideStepTitle?: boolean
length: number
class?: string
}
export let error: number | undefined = undefined
export let index: number
export let subIndex: number | undefined
export let subLength: number | undefined
export let nextInProgress: boolean = false
// Used for displaying progress of subjob of flow
export let subIndexIsPercent: boolean = false
// Remove padding/margin, border radius and titles
// Used in individual job test runs
export let compact: boolean = false
// Removes `Step 1` and replaces it with `Running`
export let hideStepTitle: boolean = false
export let length: number
let {
error = undefined,
index,
subIndex,
subLength,
nextInProgress = false,
subIndexIsPercent = false,
compact = false,
hideStepTitle = false,
length,
class: className = ''
}: Props = $props()
let duration = 200
let percent = getTween(0, duration)
let percent = new Tween(0, { duration, easing: linear })
export function resetP() {
percent = getTween(0, duration)
percent.set(0, { duration: 0 })
}
$: percent.set(
(length
? index / length + (subIndex && subLength ? subIndex / (subLength ?? 1) / length : 0)
: 0) * 100
)
$effect(() => {
percent.set(
(length
? index / length + (subIndex && subLength ? subIndex / (subLength ?? 1) / length : 0)
: 0) * 100
)
})
function getPercent(partIndex: number, _pct: number) {
if (!length) {
return 0
}
const res = Math.min(($percent - (partIndex / length) * 100) * length, 100)
const res = Math.min((percent.current - (partIndex / length) * 100) * length, 100)
return res
}
$: finished = index == length
let finished = $derived(index == length)
</script>
<div class={$$props.class}>
<div class={className}>
{#if !compact}
<div
class="flex justify-between items-end font-medium mb-1 {error != undefined
? 'text-red-700 dark:text-red-200'
: 'text-blue-700 dark:text-blue-200'}"
>
<span class="text-base">
{error != undefined
? 'Error occured'
: finished
? 'Done'
: hideStepTitle
? `Running`
: subIndexIsPercent
? `Step ${index + 1} (${subIndex !== undefined ? `${subIndex}%)` : ''}`
: `Step ${index + 1}${subIndex !== undefined ? `.${subIndex + 1}` : ''}`}
</span>
<span class="text-sm">
{$percent.toFixed(0)}%
</span>
</div>
<div
class="flex justify-between items-end font-medium mb-1 {error != undefined
? 'text-red-700 dark:text-red-200'
: 'text-blue-700 dark:text-blue-200'}"
>
<span class="text-base">
{error != undefined
? 'Error occured'
: finished
? 'Done'
: hideStepTitle
? `Running`
: subIndexIsPercent
? `Step ${index + 1} (${subIndex !== undefined ? `${subIndex}%)` : ''}`
: `Step ${index + 1}${subIndex !== undefined ? `.${subIndex + 1}` : ''}`}
</span>
<span class="text-sm">
{percent.current.toFixed(0)}%
</span>
</div>
{/if}
<!-- {#each state as step, index}
{index} {JSON.stringify(step)}
@@ -82,10 +93,12 @@
{getPercent(index)}
|
{/each} -->
<div class={twMerge(
"flex w-full bg-gray-200 overflow-hidden",
(compact) ? "rounded-none h-3" : "rounded-full h-4",
)}>
<div
class={twMerge(
'flex w-full bg-gray-200 overflow-hidden',
compact ? 'rounded-none h-3' : 'rounded-full h-4'
)}
>
{#each new Array(length) as _, partIndex (partIndex)}
<div class="h-full relative border-white {partIndex === 0 ? '' : 'border-l'} w-full">
{#if partIndex == index && nextInProgress}
@@ -101,7 +114,7 @@
class="absolute left-0 bottom-0 h-full {error == partIndex
? 'bg-red-400'
: 'bg-blue-400'}"
style="width: {getPercent(partIndex, $percent)}%"
style="width: {getPercent(partIndex, percent.current)}%"
></div>
{/if}
</div>