diff --git a/frontend/src/lib/components/RunChart.svelte b/frontend/src/lib/components/RunChart.svelte index 47453689ab..097f2aa3c9 100644 --- a/frontend/src/lib/components/RunChart.svelte +++ b/frontend/src/lib/components/RunChart.svelte @@ -23,6 +23,7 @@ export let minTimeSet: string | undefined = undefined export let maxTimeSet: string | undefined = undefined export let selectedIds: string[] = [] + export let canSelect: boolean = true const dispatch = createEventDispatcher() const SUCCESS_COLOR = '#4ade80' @@ -142,7 +143,7 @@ } function highlightSelectedPoints(ids: string[]) { - if (ids.length === 0) { + if (!canSelect || ids.length === 0) { data.datasets[0].backgroundColor = FAIL_COLOR data.datasets[1].backgroundColor = SUCCESS_COLOR } else { @@ -237,8 +238,10 @@ } }, onClick: (e, u) => { - const ids = u.map((j) => data.datasets[j.datasetIndex].data[j.index].id) - selectedIds = ids + if (canSelect) { + const ids = u.map((j) => data.datasets[j.datasetIndex].data[j.index].id) + selectedIds = ids + } }, scales: { @@ -265,7 +268,6 @@ } as any $: data && scatterOptions && highlightSelectedPoints(selectedIds) - + +
+
+
+ Select all
- {:else if $workspaceStore !== 'admins' && omittedObscuredJobs} -
- {jobs && jobCountString(jobs.length)} - - - - Too specific filtering may have caused the omission of obscured jobs. This is done for - security reasons. To see obscured jobs, try removing some filters. - - -
- {:else} -
{jobs && jobCountString(jobs.length)}
{/if} -
Timestamp
-
Path
- {#if containsLabel} -
Label
- {/if} -
Triggered by
+
+ {#if showExternalJobs && externalJobs.length > 0} +
+
+ {jobs && jobCountString(jobs.length + externalJobs.length)}{externalJobs.length} jobs obscured +
+
+ {:else if $workspaceStore !== 'admins' && omittedObscuredJobs} +
+ {jobs && jobCountString(jobs.length)} + + + + Too specific filtering may have caused the omission of obscured jobs. This is done for + security reasons. To see obscured jobs, try removing some filters. + + +
+ {:else} +
{jobs && jobCountString(jobs.length)}
+ {/if} +
Timestamp
+
Path
+ {#if containsLabel} +
Label
+ {/if} +
Triggered by
+
j.id) ?? [] - if (selectedIds.length === 0 ) { - sendUserToast("There are no visible jobs that can be canceled", true) + if (selectedIds.length === 0) { + sendUserToast('There are no visible jobs that can be canceled', true) } } async function cancelFilteredJobs() { isCancelingFilteredJobs = true fetchingFilteredJobs = true const selectedFilters = { - workspace: $workspaceStore ?? '', - startedBefore: maxTs, - startedAfter: minTs, - schedulePath, - scriptPathExact: path === null || path === '' ? undefined : path, - createdBy: user === null || user === '' ? undefined : user, - scriptPathStart: folder === null || folder === '' ? undefined : `f/${folder}/`, - jobKinds, - success: success == 'success' ? true : success == 'failure' ? false : undefined, - running: success == 'running' ? true : undefined, - isNotSchedule: showSchedules == false ? true : undefined, - scheduledForBeforeNow: showFutureJobs == false ? true : undefined, - args: - argFilter && argFilter != '{}' && argFilter != '' && argError == '' - ? argFilter - : undefined, - result: - resultFilter && resultFilter != '{}' && resultFilter != '' && resultError == '' - ? resultFilter - : undefined, - allWorkspaces: allWorkspaces ? true : undefined, - concurrencyKey: concurrencyKey ?? undefined - } + workspace: $workspaceStore ?? '', + startedBefore: maxTs, + startedAfter: minTs, + schedulePath, + scriptPathExact: path === null || path === '' ? undefined : path, + createdBy: user === null || user === '' ? undefined : user, + scriptPathStart: folder === null || folder === '' ? undefined : `f/${folder}/`, + jobKinds, + success: success == 'success' ? true : success == 'failure' ? false : undefined, + running: success == 'running' ? true : undefined, + isNotSchedule: showSchedules == false ? true : undefined, + scheduledForBeforeNow: showFutureJobs == false ? true : undefined, + args: + argFilter && argFilter != '{}' && argFilter != '' && argError == '' ? argFilter : undefined, + result: + resultFilter && resultFilter != '{}' && resultFilter != '' && resultError == '' + ? resultFilter + : undefined, + allWorkspaces: allWorkspaces ? true : undefined, + concurrencyKey: concurrencyKey ?? undefined + } selectedFiltersString = JSON.stringify(selectedFilters, null, 4) jobIdsToCancel = await JobService.listFilteredUuids(selectedFilters) @@ -386,6 +384,11 @@ return j.type === 'QueuedJob' && !j.schedule_path } + function jobCountString(count: number) { + + return `${count} ${count == 1 ? 'job': 'jobs'}` + } + const warnJobLimitMsg = 'The exact number of concurrent job at the beginning of the time range may be incorrect as only the last 1000 jobs are taken into account: a job that was started earlier than this limit will not be taken into account' @@ -394,9 +397,6 @@ extendedJobs !== undefined && extendedJobs.jobs.length + extendedJobs.obscured_jobs.length >= 1000 - $: if (selectedIds.length === 0) { - isSelectingJobsToCancel = false - } { @@ -556,6 +556,7 @@ {#if graph === 'RunChart'} {#if isSelectingJobsToCancel}
-
{:else if !$userStore?.is_admin && !$superadmin} {#if isSelectingJobsToCancel}
-
{:else if !$userStore?.is_admin && !$superadmin}