diff --git a/frontend/src/lib/components/FlowStatusViewerInner.svelte b/frontend/src/lib/components/FlowStatusViewerInner.svelte index 006016caa2..7d76cf6964 100644 --- a/frontend/src/lib/components/FlowStatusViewerInner.svelte +++ b/frontend/src/lib/components/FlowStatusViewerInner.svelte @@ -24,7 +24,7 @@ import ModuleStatus from './ModuleStatus.svelte' import { clone, isScriptPreview, msToSec, readFieldsRecursively, truncateRev } from '$lib/utils' import JobArgs from './JobArgs.svelte' - import { ChevronDown, ExternalLink, Hourglass } from 'lucide-svelte' + import { ChevronDown, ExternalLink, Hourglass, Hash } from 'lucide-svelte' import { deepEqual } from 'fast-equals' import FlowTimeline from './FlowTimeline.svelte' import { dfs } from './flows/dfs' @@ -1295,6 +1295,21 @@ let totalEventsWaiting = $derived( Object.values(suspendStatus?.val ?? {}).reduce((a, b) => a + (b?.nb ?? 0), 0) ) + + // Hash navigation functions + function scrollToSection(sectionId: string) { + const element = document.getElementById(sectionId) + if (element) { + element.scrollIntoView({ behavior: 'smooth' }) + } + } + + function handleSectionHashClick(sectionId: string) { + const url = new URL(window.location.href) + url.hash = sectionId + window.history.pushState({}, '', url.toString()) + scrollToSection(sectionId) + } @@ -1375,8 +1390,20 @@ {:else} -

Result

-
+
+

+ Result + +

+
+
{#if job !== undefined && (job.result_stream || (job.type == 'CompletedJob' && 'result' in job && job.result !== undefined))} job?.raw_flow?.modules ?? [] }) @@ -354,6 +358,29 @@ } } + // Hash navigation functions + function scrollToSection(sectionId: string) { + const element = document.getElementById(sectionId) + if (element) { + element.scrollIntoView({ behavior: 'smooth' }) + } + } + + function handleSectionHashClick(sectionId: string) { + const url = new URL(window.location.href) + url.hash = sectionId + window.history.pushState({}, '', url.toString()) + currentHash = sectionId + scrollToSection(sectionId) + } + + function handleHashChange() { + currentHash = window.location.hash.slice(1) // Remove the # symbol + if (currentHash) { + scrollToSection(currentHash) + } + } + $effect(() => { job?.id && lastJobId !== job.id && untrack(() => getConcurrencyKey(job)) }) @@ -369,6 +396,19 @@ $effect(() => { job && untrack(() => onJobLoaded()) }) + $effect(() => { + // Initialize hash on mount and listen for hash changes + currentHash = window.location.hash.slice(1) + if (currentHash) { + // Small delay to ensure DOM is rendered + setTimeout(() => scrollToSection(currentHash), 100) + } + + window.addEventListener('hashchange', handleHashChange) + return () => { + window.removeEventListener('hashchange', handleHashChange) + } + }) @@ -714,8 +754,18 @@ {/if} -
-
Inputs
+
+
+ Inputs + +
{#if job} -
-

Result

-
+
+

+ Result + +

+
{#if job.result_stream || (job.type == 'CompletedJob' && job.result !== undefined)} -
+
+
+ Logs & Metrics + +