From 0c739a7542bc0961ae0ca393bc39d5431d5f2c42 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 26 Feb 2026 18:18:54 +0000 Subject: [PATCH] fix: runs page date picker query parameter handling - Route query params by job status: queue-only statuses (running/suspended/waiting) use createdBeforeQueue/createdAfterQueue, completed-only statuses (success/failure) skip queue params, and no filter uses both - Pass completedAfter (extendedMinTs) on initial load to avoid overfetching - Skip auto-refresh syncer for manual timeframes (fixed past date ranges) - Debounce param change effect to prevent double API calls - Remove redundant timeframe dependency from effect (already tracked via filters) Co-Authored-By: Claude Opus 4.6 --- .../components/runs/useJobsLoader.svelte.ts | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/frontend/src/lib/components/runs/useJobsLoader.svelte.ts b/frontend/src/lib/components/runs/useJobsLoader.svelte.ts index b4cb93d94b..9f159707aa 100644 --- a/frontend/src/lib/components/runs/useJobsLoader.svelte.ts +++ b/frontend/src/lib/components/runs/useJobsLoader.svelte.ts @@ -109,6 +109,7 @@ export function useJobsLoader(args: () => UseJobLoaderArgs) { let intervalId: ReturnType | undefined = $state() let sync = true + let paramChangeTimeout: ReturnType | undefined function onParamChanges() { resetJobs() @@ -180,11 +181,18 @@ export function useJobsLoader(args: () => UseJobLoaderArgs) { loadingFetch = true let scriptPathStart = folder == null || folder === '' ? undefined : `f/${folder}/` let scriptPathExact = path == null || path === '' ? undefined : path + let isQueueOnly = success == 'running' || success == 'suspended' || success == 'waiting' + let isCompletedOnly = success == 'success' || success == 'failure' let promise = JobService.listJobs({ workspace: currentWorkspace, - completedBefore: completedBefore ?? undefined, - completedAfter: completedAfter ?? undefined, - createdAfterQueue, + completedBefore: isQueueOnly ? undefined : (completedBefore ?? undefined), + completedAfter: isQueueOnly ? undefined : (completedAfter ?? undefined), + createdBeforeQueue: isQueueOnly ? (completedBefore ?? undefined) : undefined, + createdAfterQueue: isCompletedOnly + ? undefined + : isQueueOnly + ? (completedAfter ?? createdAfterQueue) + : createdAfterQueue, schedulePath: schedulePath ?? undefined, scriptPathExact, createdBy: user == null || user === '' ? undefined : user, @@ -311,16 +319,19 @@ export function useJobsLoader(args: () => UseJobLoaderArgs) { const extendedMinTs = subtractDaysFromDateString(minTs, lookback) if (concurrencyKey == null || concurrencyKey === '') { - return CancelablePromiseUtils.map(fetchJobs(maxTs, null, extendedMinTs), (newJobs) => { - extendedJobs = { jobs: newJobs, obscured_jobs: [] } as ExtendedJobs + return CancelablePromiseUtils.map( + fetchJobs(maxTs, extendedMinTs ?? null, extendedMinTs), + (newJobs) => { + extendedJobs = { jobs: newJobs, obscured_jobs: [] } as ExtendedJobs - // Filter on minTs here and not in the backend - // to get enough data for the concurrency graph - jobs = sortMinDate(minTs, newJobs) - externalJobs = [] - computeCompletedJobs() - loading = false - }) + // Filter on minTs here and not in the backend + // to get enough data for the concurrency graph + jobs = sortMinDate(minTs, newJobs) + externalJobs = [] + computeCompletedJobs() + loading = false + } + ) } else { return CancelablePromiseUtils.map( fetchExtendedJobs(concurrencyKey, maxTs, extendedMinTs ?? null), @@ -379,6 +390,9 @@ export function useJobsLoader(args: () => UseJobLoaderArgs) { if (loadingFetch) { return } + if (timeframe?.type === 'manual') { + return + } if (sync) { if (syncQueuedRunsCount) { getCount() @@ -526,12 +540,18 @@ export function useJobsLoader(args: () => UseJobLoaderArgs) { Object.keys(filters ?? {}).map((k) => filters?.[k as keyof RunsFilterInstance]) currentWorkspace lookback - timeframe perPage showSchedules showFutureJobs - let p = untrack(() => onParamChanges()) - return () => p.cancel() + let p: CancelablePromise | undefined + clearTimeout(paramChangeTimeout) + paramChangeTimeout = setTimeout(() => { + p = untrack(() => onParamChanges()) + }, 0) + return () => { + clearTimeout(paramChangeTimeout) + p?.cancel() + } }) $effect(() => { ;[autoRefresh, refreshRate]