From 8950aae44e350abe58733cf4cf67f4755c671756 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 13 Aug 2024 10:41:36 +0200 Subject: [PATCH] feat(frontend): improve display of waiting jobs + schedule filter + suspended jobs on runs page --- ...391bc2e5c44e0953103790dfe9375f605ee65.json | 29 ++++ ...7f5033b9c9afc344d9c3e385ba20a3ad2197a.json | 2 +- ...2acfc0ed4973309b4860e93882a37a21a0bd0.json | 23 ---- ...0cb549a34b96554ae1872355b90304f5dcb76.json | 4 +- ...4828611591c76dd32541735095c010d6cdf2.json} | 10 +- backend/windmill-api/openapi.yaml | 3 + backend/windmill-api/src/jobs.rs | 6 +- .../src/lib/components/runs/JobLoader.svelte | 30 +++-- .../lib/components/runs/QueuePopover.svelte | 2 +- .../src/lib/components/runs/RunRow.svelte | 11 ++ .../src/lib/components/runs/RunsFilter.svelte | 98 +++++++++++--- .../src/lib/components/runs/RunsQueue.svelte | 35 +++-- .../src/lib/components/runs/RunsTable.svelte | 127 +++++++++--------- .../(logged)/runs/[...path]/+page.svelte | 88 +++++++++--- .../(root)/(logged)/schedules/+page.svelte | 2 +- 15 files changed, 323 insertions(+), 147 deletions(-) create mode 100644 backend/.sqlx/query-44d0c89afbc472165d80ca7a14b391bc2e5c44e0953103790dfe9375f605ee65.json delete mode 100644 backend/.sqlx/query-8481d1bd91b7d23f946b4cf0d312acfc0ed4973309b4860e93882a37a21a0bd0.json rename backend/.sqlx/{query-f5681df5935ec753f4a6d9ab8b927bbf890f0b4fe2de16dc764b24f24d7bbdca.json => query-bf04a017bc55f6e1f5f25f697b3c4828611591c76dd32541735095c010d6cdf2.json} (57%) diff --git a/backend/.sqlx/query-44d0c89afbc472165d80ca7a14b391bc2e5c44e0953103790dfe9375f605ee65.json b/backend/.sqlx/query-44d0c89afbc472165d80ca7a14b391bc2e5c44e0953103790dfe9375f605ee65.json new file mode 100644 index 0000000000..4005465103 --- /dev/null +++ b/backend/.sqlx/query-44d0c89afbc472165d80ca7a14b391bc2e5c44e0953103790dfe9375f605ee65.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND running = false", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "database_length!", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "suspended!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool" + ] + }, + "nullable": [ + null, + null + ] + }, + "hash": "44d0c89afbc472165d80ca7a14b391bc2e5c44e0953103790dfe9375f605ee65" +} diff --git a/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json b/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json index 1fa370e682..75b8108281 100644 --- a/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json +++ b/backend/.sqlx/query-661f472ff3860983322162420457f5033b9c9afc344d9c3e385ba20a3ad2197a.json @@ -5,7 +5,7 @@ "columns": [ { "ordinal": 0, - "name": "bool", + "name": "?column?", "type_info": "Bool" } ], diff --git a/backend/.sqlx/query-8481d1bd91b7d23f946b4cf0d312acfc0ed4973309b4860e93882a37a21a0bd0.json b/backend/.sqlx/query-8481d1bd91b7d23f946b4cf0d312acfc0ed4973309b4860e93882a37a21a0bd0.json deleted file mode 100644 index 2ec3af2410..0000000000 --- a/backend/.sqlx/query-8481d1bd91b7d23f946b4cf0d312acfc0ed4973309b4860e93882a37a21a0bd0.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT coalesce(COUNT(*), 0) as \"database_length!\" FROM queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND running = false", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "database_length!", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Text", - "Bool" - ] - }, - "nullable": [ - null - ] - }, - "hash": "8481d1bd91b7d23f946b4cf0d312acfc0ed4973309b4860e93882a37a21a0bd0" -} diff --git a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json index 54e94cfb8f..99269c9851 100644 --- a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json +++ b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json @@ -18,8 +18,8 @@ "Left": [] }, "nullable": [ - false, - true + true, + false ] }, "hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76" diff --git a/backend/.sqlx/query-f5681df5935ec753f4a6d9ab8b927bbf890f0b4fe2de16dc764b24f24d7bbdca.json b/backend/.sqlx/query-bf04a017bc55f6e1f5f25f697b3c4828611591c76dd32541735095c010d6cdf2.json similarity index 57% rename from backend/.sqlx/query-f5681df5935ec753f4a6d9ab8b927bbf890f0b4fe2de16dc764b24f24d7bbdca.json rename to backend/.sqlx/query-bf04a017bc55f6e1f5f25f697b3c4828611591c76dd32541735095c010d6cdf2.json index ff9a63f614..aad7404583 100644 --- a/backend/.sqlx/query-f5681df5935ec753f4a6d9ab8b927bbf890f0b4fe2de16dc764b24f24d7bbdca.json +++ b/backend/.sqlx/query-bf04a017bc55f6e1f5f25f697b3c4828611591c76dd32541735095c010d6cdf2.json @@ -1,12 +1,17 @@ { "db_name": "PostgreSQL", - "query": "SELECT coalesce(COUNT(*), 0) as \"database_length!\" FROM completed_job WHERE workspace_id = $1", + "query": "SELECT coalesce(COUNT(*), 0) as \"database_length!\", null::bigint as suspended FROM completed_job WHERE workspace_id = $1", "describe": { "columns": [ { "ordinal": 0, "name": "database_length!", "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "suspended", + "type_info": "Int8" } ], "parameters": { @@ -15,8 +20,9 @@ ] }, "nullable": [ + null, null ] }, - "hash": "f5681df5935ec753f4a6d9ab8b927bbf890f0b4fe2de16dc764b24f24d7bbdca" + "hash": "bf04a017bc55f6e1f5f25f697b3c4828611591c76dd32541735095c010d6cdf2" } diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 67e45b2c22..31c91f4c16 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -5631,6 +5631,8 @@ paths: properties: database_length: type: integer + suspended: + type: integer required: - database_length @@ -5812,6 +5814,7 @@ paths: - $ref: "#/components/parameters/CreatedOrStartedAfter" - $ref: "#/components/parameters/CreatedOrStartedAfterCompletedJob" - $ref: "#/components/parameters/JobKinds" + - $ref: "#/components/parameters/Suspended" - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/ResultFilter" diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index c102ec6fb4..43db962e6a 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -1462,7 +1462,6 @@ async fn cancel_selection( Path(w_id): Path, Json(jobs): Json>, ) -> error::JsonResult> { - let mut tx = user_db.begin(&authed).await?; let jobs_to_cancel = sqlx::query_scalar!( "SELECT id FROM queue WHERE id = ANY($1) AND schedule_path IS NULL", @@ -1508,6 +1507,7 @@ async fn list_filtered_uuids( #[derive(Serialize, Debug, FromRow)] struct QueueStats { database_length: i64, + suspended: Option, } #[derive(Deserialize)] @@ -1523,7 +1523,7 @@ async fn count_queue_jobs( Ok(Json( sqlx::query_as!( QueueStats, - "SELECT coalesce(COUNT(*), 0) as \"database_length!\" FROM queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND running = false", + "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now()", w_id, w_id == "admins" && cq.all_workspaces.unwrap_or(false), ) @@ -1539,7 +1539,7 @@ async fn count_completed_jobs( Ok(Json( sqlx::query_as!( QueueStats, - "SELECT coalesce(COUNT(*), 0) as \"database_length!\" FROM completed_job WHERE workspace_id = $1", + "SELECT coalesce(COUNT(*), 0) as \"database_length!\", null::bigint as suspended FROM completed_job WHERE workspace_id = $1", w_id ) .fetch_one(&db) diff --git a/frontend/src/lib/components/runs/JobLoader.svelte b/frontend/src/lib/components/runs/JobLoader.svelte index 463f1ca7b7..57609dab9c 100644 --- a/frontend/src/lib/components/runs/JobLoader.svelte +++ b/frontend/src/lib/components/runs/JobLoader.svelte @@ -20,7 +20,7 @@ export let label: string | null = null export let folder: string | null export let path: string | null - export let success: 'success' | 'failure' | 'running' | undefined = undefined + export let success: 'success' | 'suspended' | 'waiting' | 'failure' | 'running' | undefined = undefined export let isSkipped: boolean = false export let showSchedules: boolean = true export let showFutureJobs: boolean = true @@ -32,6 +32,8 @@ export let maxTs: string | undefined = undefined export let jobKinds: string = '' export let queue_count: Tweened | undefined = undefined + export let suspended_count: Tweened | undefined = undefined + export let autoRefresh: boolean = true export let completedJobs: CompletedJob[] | undefined = undefined export let externalJobs: Job[] | undefined = undefined @@ -63,6 +65,7 @@ lookback && user && folder && + schedulePath != undefined && showFutureJobs != undefined && showSchedules != undefined && allWorkspaces != undefined && @@ -137,17 +140,18 @@ scriptPathStart: scriptPathStart, jobKinds, success: success == 'success' ? true : success == 'failure' ? false : undefined, - running: success == 'running' ? true : undefined, + running: (success == 'running' || success == 'suspended' ) ? true : (success == 'waiting' ) ? false : undefined, isSkipped: isSkipped ? undefined : false, // isFlowStep: jobKindsCat != 'all' ? false : undefined, hasNullParent: - scriptPathExact != undefined || scriptPathStart != undefined || jobKinds != 'all' + scriptPathExact != undefined || scriptPathStart != undefined || jobKindsCat != 'all' ? true : undefined, label: label === null || label === '' ? undefined : label, tag: tag === null || tag === '' ? undefined : tag, isNotSchedule: showSchedules == false ? true : undefined, - scheduledForBeforeNow: showFutureJobs == false ? true : undefined, + suspended: success == 'waiting' ? false : success == 'suspended' ? true : undefined, + scheduledForBeforeNow: showFutureJobs == false || (success == 'waiting' || success == 'suspended') ? true : undefined, args: argFilter && argFilter != '{}' && argFilter != '' && argError == '' ? argFilter @@ -292,16 +296,26 @@ } async function getCount() { - const qc = (await JobService.getQueueCount({ workspace: $workspaceStore!, allWorkspaces })) - .database_length + const { database_length, suspended} = (await JobService.getQueueCount({ workspace: $workspaceStore!, allWorkspaces })) + if (queue_count) { - queue_count.set(qc) + queue_count.set(database_length) } else { - queue_count = tweened(qc, { duration: 1000 }) + queue_count = tweened(database_length, { duration: 1000 }) + } + if (suspended_count) { + suspended_count.set(suspended ?? 0) + } else { + suspended_count = tweened(suspended ?? 0, { duration: 1000 }) + } } async function syncer() { + if (success == 'waiting') { + minTs = undefined + maxTs = undefined + } if (loadingFetch) { return } diff --git a/frontend/src/lib/components/runs/QueuePopover.svelte b/frontend/src/lib/components/runs/QueuePopover.svelte index 651e0f6858..aa42e269e3 100644 --- a/frontend/src/lib/components/runs/QueuePopover.svelte +++ b/frontend/src/lib/components/runs/QueuePopover.svelte @@ -33,7 +33,7 @@
Only showing the first 100 jobs
{/if} - {#each jobs.slice(0, 100) as job} + {#each jobs.slice(0, 1000) as job} + {:else}
diff --git a/frontend/src/lib/components/runs/RunsFilter.svelte b/frontend/src/lib/components/runs/RunsFilter.svelte index 095467b69c..c130d8a5e2 100644 --- a/frontend/src/lib/components/runs/RunsFilter.svelte +++ b/frontend/src/lib/components/runs/RunsFilter.svelte @@ -4,7 +4,7 @@ import ToggleButtonGroup from '../common/toggleButton-v2/ToggleButtonGroup.svelte' import Tooltip from '../Tooltip.svelte' import AutoComplete from 'simple-svelte-autocomplete' - import { AlertCircle, CheckCircle2, ChevronDown, Filter, PlayCircle, X } from 'lucide-svelte' + import { AlertCircle, CheckCircle2, ChevronDown, Filter, Hourglass, PlayCircle, X } from 'lucide-svelte' import JsonEditor from '../apps/editor/settingsPanel/inputEditor/JsonEditor.svelte' import Toggle from '../Toggle.svelte' import Label from '../Label.svelte' @@ -19,7 +19,7 @@ export let label: string | null = null export let concurrencyKey: string | null = null export let tag: string | null = null - export let success: 'running' | 'success' | 'failure' | undefined = undefined + export let success: 'running' | 'waiting' | 'suspended' | 'queued' | 'success' | 'failure' | undefined = undefined export let isSkipped: boolean | undefined = undefined export let argFilter: string export let argError: string @@ -29,6 +29,7 @@ export let user: string | null = null export let folder: string | null = null export let mobile: boolean = false + export let schedulePath: string | undefined // Autocomplete data export let paths: string[] = [] @@ -39,35 +40,42 @@ $: displayedLabel = label $: displayedConcurrencyKey = concurrencyKey $: displayedTag = tag + $: displayedSchedule = schedulePath let copyArgFilter = argFilter let copyResultFilter = resultFilter - export let filterBy: 'path' | 'user' | 'folder' | 'label' | 'concurrencyKey' | 'tag' = 'path' + export let filterBy: 'path' | 'user' | 'folder' | 'label' | 'concurrencyKey' | 'tag' | 'schedulePath' = 'path' const dispatch = createEventDispatcher() - let manuallySet = false + let autoSet = false - $: { + + $: (path || user || folder || label || concurrencyKey || tag || schedulePath) && autosetFilter() + + function autosetFilter() { if (path !== null && path !== '' && filterBy !== 'path') { - manuallySet = true + autoSet = true filterBy = 'path' } else if (user !== null && user !== '' && filterBy !== 'user') { - manuallySet = true + autoSet = true filterBy = 'user' } else if (folder !== null && folder !== '' && filterBy !== 'folder') { - manuallySet = true + autoSet = true filterBy = 'folder' } else if (label !== null && label !== '' && filterBy !== 'label') { - manuallySet = true + autoSet = true filterBy = 'label' } else if (concurrencyKey !== null && concurrencyKey !== '' && filterBy !== 'concurrencyKey') { - manuallySet = true + autoSet = true filterBy = 'concurrencyKey' } else if (tag !== null && tag !== '' && filterBy !== 'tag') { - manuallySet = true + autoSet = true filterBy = 'tag' + } else if (schedulePath !== undefined && schedulePath !== '' && filterBy !== 'schedulePath') { + autoSet = true + filterBy = 'schedulePath' } } @@ -75,7 +83,8 @@ let concurrencyKeyTimeout: NodeJS.Timeout | undefined = undefined let tagTimeout: NodeJS.Timeout | undefined = undefined - +{autoSet} +{filterBy}
{#if !mobile}
@@ -94,15 +103,16 @@ { - if (!manuallySet) { + if (!autoSet) { path = null user = null folder = null label = null concurrencyKey = null tag = null + schedulePath = undefined } else { - manuallySet = false + autoSet = false } }} > @@ -111,7 +121,8 @@
{/key} + {:else if filterBy === 'schedulePath'} + {#key tag} +
+ {#if tag} + + {/if} + Schedule Path + + { + if (tagTimeout) { + clearTimeout(tagTimeout) + } + + tagTimeout = setTimeout(() => { + schedulePath = displayedSchedule + }, 1000) + }} + /> +
+ {/key} {/if}
@@ -393,6 +437,23 @@ icon={AlertCircle} iconProps={{ color: success === 'failure' ? 'red' : 'gray' }} /> + {#if success == 'waiting'} + + {:else if success == 'suspended'} + + {/if}
{/if} @@ -419,24 +480,27 @@ { - if (!manuallySet) { + if (!autoSet) { path = null user = null folder = null label = null concurrencyKey = null tag = null + schedulePath = undefined } else { - manuallySet = false + autoSet = false } }} > + + diff --git a/frontend/src/lib/components/runs/RunsQueue.svelte b/frontend/src/lib/components/runs/RunsQueue.svelte index cf490df410..8c5090135b 100644 --- a/frontend/src/lib/components/runs/RunsQueue.svelte +++ b/frontend/src/lib/components/runs/RunsQueue.svelte @@ -1,23 +1,36 @@ + +
-
Jobs waiting for a worker
+
Waiting for workers Jobs waiting for a worker being available to be executed
{queue_count ? ($queue_count ?? 0).toFixed(0) : '...'}
-
+
{#if queue_count && ($queue_count ?? 0) > 0} - - - jobs - - - + {/if} +
+ +{#if suspended_count && ($suspended_count ?? 0) > 0} +
+
Suspended Jobs waiting for an event or approval before being resumed
+
{suspended_count ? ($suspended_count ?? 0).toFixed(0) : '...'}
+
+ +
+
+{/if} diff --git a/frontend/src/lib/components/runs/RunsTable.svelte b/frontend/src/lib/components/runs/RunsTable.svelte index 6a39d36fd8..e8858e8d72 100644 --- a/frontend/src/lib/components/runs/RunsTable.svelte +++ b/frontend/src/lib/components/runs/RunsTable.svelte @@ -228,73 +228,74 @@
Triggered by
+ {#if jobs?.length == 0 && (!showExternalJobs || externalJobs?.length == 0)} + + +
No jobs found for the selected filters.
+ + + {:else} + +
+ {#if flatJobs} + {@const jobOrDate = flatJobs[index]} - -
- {#if flatJobs} - {@const jobOrDate = flatJobs[index]} - - {#if jobOrDate} - {#if jobOrDate?.type === 'date'} -
- {jobOrDate.date} -
- {:else} -
- { - const jobId = jobOrDate.job.id - if (isSelectingJobsToCancel) { - if (selectedIds.includes(jobOrDate.job.id)) { - selectedIds = selectedIds.filter((id) => id != jobId) + {#if jobOrDate} + {#if jobOrDate?.type === 'date'} +
+ {jobOrDate.date} +
+ {:else} +
+ { + const jobId = jobOrDate.job.id + if (isSelectingJobsToCancel) { + if (selectedIds.includes(jobOrDate.job.id)) { + selectedIds = selectedIds.filter((id) => id != jobId) + } else { + selectedIds.push(jobId) + selectedIds = selectedIds + } } else { - selectedIds.push(jobId) - selectedIds = selectedIds + selectedWorkspace = jobOrDate.job.workspace_id + selectedIds = [jobOrDate.job.id] + dispatch('select') } - } else { - selectedWorkspace = jobOrDate.job.workspace_id - selectedIds = [jobOrDate.job.id] - dispatch('select') - } - }} - {activeLabel} - on:filterByLabel - on:filterByPath - on:filterByUser - on:filterByFolder - on:filterByConcurrencyKey - {containerWidth} - /> -
+ }} + {activeLabel} + on:filterByLabel + on:filterByPath + on:filterByUser + on:filterByFolder + on:filterByConcurrencyKey + on:filterBySchedule + {containerWidth} + /> +
+ {/if} + {:else} + {JSON.stringify(jobOrDate)} {/if} {:else} - {JSON.stringify(jobOrDate)} +
+
...
+
...
+
...
+
...
+
{/if} - {:else} -
-
...
-
...
-
...
-
...
-
- {/if} -
-
+
+
+ {/if} -{#if jobs?.length == 0 && (!showExternalJobs || externalJobs?.length == 0)} - - -
No jobs found for the selected filters.
- - -{/if} diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte index fc6326f0ec..020eaa6f88 100644 --- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte @@ -51,7 +51,7 @@ let concurrencyKey: string | null = $page.url.searchParams.get('concurrency_key') let tag: string | null = $page.url.searchParams.get('tag') // Rest of filters handled by RunsFilter - let success: 'running' | 'success' | 'failure' | undefined = ($page.url.searchParams.get( + let success: 'running' | 'suspended' | 'waiting' | 'success' | 'failure' | undefined = ($page.url.searchParams.get( 'success' ) ?? undefined) as 'running' | 'success' | 'failure' | undefined let isSkipped: boolean | undefined = @@ -87,6 +87,8 @@ let allWorkspaces = $page.url.searchParams.get('all_workspaces') == 'true' ?? false let queue_count: Tweened | undefined = undefined + let suspended_count: Tweened | undefined = undefined + let jobKinds: string | undefined = undefined let loading: boolean = false let paths: string[] = [] @@ -255,8 +257,6 @@ function reset() { minTs = undefined maxTs = undefined - - autoRefresh = true jobs = undefined completedJobs = undefined selectedManualDate = 0 @@ -296,6 +296,8 @@ label = null concurrencyKey = null tag = null + schedulePath = undefined + } function filterByUser(e: CustomEvent) { @@ -305,6 +307,7 @@ label = null concurrencyKey = null tag = null + schedulePath = undefined } function filterByFolder(e: CustomEvent) { @@ -314,6 +317,7 @@ label = null concurrencyKey = null tag = null + schedulePath = undefined } function filterByLabel(e: CustomEvent) { @@ -323,6 +327,7 @@ label = e.detail concurrencyKey = null tag = null + schedulePath = undefined } function filterByConcurrencyKey(e: CustomEvent) { @@ -332,6 +337,7 @@ label = null concurrencyKey = e.detail tag = null + schedulePath = undefined } function filterByTag(e: CustomEvent) { @@ -341,6 +347,17 @@ label = null concurrencyKey = null tag = e.detail + schedulePath = undefined + } + + function filterBySchedule(e: CustomEvent) { + path = null + user = null + folder = null + label = null + concurrencyKey = null + tag = null + schedulePath = e.detail } let calendarChangeTimeout: NodeJS.Timeout | undefined = undefined @@ -381,18 +398,27 @@ scriptPathStart: folder === null || folder === '' ? undefined : `f/${folder}/`, jobKinds, success: success == 'success' ? true : success == 'failure' ? false : undefined, - running: success == 'running' ? true : undefined, + running: (success == 'running' || success == 'suspended' ) ? true : (success == 'waiting' ) ? false : undefined, + isSkipped: isSkipped ? undefined : false, + // isFlowStep: jobKindsCat != 'all' ? false : undefined, + hasNullParent: + path != undefined || path != undefined || jobKindsCat != 'all' + ? true + : undefined, + label: label === null || label === '' ? undefined : label, + tag: tag === null || tag === '' ? undefined : tag, isNotSchedule: showSchedules == false ? true : undefined, - scheduledForBeforeNow: showFutureJobs == false ? true : undefined, + suspended: success == 'waiting' ? false : success == 'suspended' ? true : undefined, + scheduledForBeforeNow: showFutureJobs == false || (success == 'waiting' || success == 'suspended') ? true : undefined, args: - argFilter && argFilter != '{}' && argFilter != '' && argError == '' ? argFilter : undefined, + argFilter && argFilter != '{}' && argFilter != '' && argError == '' + ? argFilter + : undefined, result: resultFilter && resultFilter != '{}' && resultFilter != '' && resultError == '' ? resultFilter : undefined, allWorkspaces: allWorkspaces ? true : undefined, - concurrencyKey: concurrencyKey ?? undefined, - tag: tag ?? undefined } selectedFiltersString = JSON.stringify(selectedFilters, null, 4) @@ -424,6 +450,24 @@ graph === 'ConcurrencyChart' && extendedJobs !== undefined && extendedJobs.jobs.length + extendedJobs.obscured_jobs.length >= 1000 + + + function jobsFilter(f: 'waiting' | 'suspended') { + path = null + user = null + folder = null + label = null + concurrencyKey = null + schedulePath = undefined + path = null + tag = null + if (success == f) { + success = undefined + } else { + success = f + } + jobKindsCat = 'all' + } -{#if innerWidth > 1280} +{#if innerWidth > 900}
@@ -556,6 +601,7 @@ bind:resultError bind:jobKindsCat bind:allWorkspaces + bind:schedulePath on:change={reloadJobsWithoutFilterError} {usernames} {folders} @@ -651,7 +697,11 @@
- + { + jobsFilter('waiting') + }} on:jobs_suspended={() => { + jobsFilter('suspended') + }} />
{#if isSelectingJobsToCancel}
@@ -724,7 +774,7 @@ localStorage.setItem('show_schedules_in_run', showSchedules ? 'true' : 'false') }} /> - CRON Schedules + Schedules
@@ -843,6 +893,7 @@ on:filterByLabel={filterByLabel} on:filterByConcurrencyKey={filterByConcurrencyKey} on:filterByTag={filterByTag} + on:filterBySchedule={filterBySchedule} /> {:else}
@@ -909,6 +960,7 @@ bind:argError bind:resultError bind:allWorkspaces + bind:schedulePath mobile={true} on:change={reloadJobsWithoutFilterError} /> @@ -992,10 +1044,14 @@ /> {/if}
-
+
{#if queue_count} - + { + jobsFilter('waiting') + }} on:jobs_suspended={() => { + jobsFilter('suspended') + }} /> {/if}
{#if isSelectingJobsToCancel} @@ -1062,7 +1118,7 @@
-
+
-
+
Planned later Max datetime