Skip to content

Commit

Permalink
feat: add label and schedule filters to runs page
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenfiszel committed Apr 23, 2024
1 parent 032de9c commit 7d557c2
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 67 deletions.
23 changes: 23 additions & 0 deletions backend/windmill-api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5248,6 +5248,11 @@ paths:
in: query
schema:
type: boolean
- name: is_not_schedule
description: is not a scheduled job
in: query
schema:
type: boolean
responses:
"200":
description: All queued jobs
Expand Down Expand Up @@ -5333,6 +5338,7 @@ paths:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/OrderDesc"
- $ref: "#/components/parameters/CreatedBy"
- $ref: "#/components/parameters/Label"
- $ref: "#/components/parameters/ParentJob"
- $ref: "#/components/parameters/ScriptExactPath"
- $ref: "#/components/parameters/ScriptStartPath"
Expand Down Expand Up @@ -5362,6 +5368,11 @@ paths:
in: query
schema:
type: boolean
- name: is_not_schedule
description: is not a scheduled job
in: query
schema:
type: boolean
responses:
"200":
description: All completed jobs
Expand All @@ -5381,6 +5392,7 @@ paths:
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/CreatedBy"
- $ref: "#/components/parameters/Label"
- $ref: "#/components/parameters/ParentJob"
- $ref: "#/components/parameters/ScriptExactPath"
- $ref: "#/components/parameters/ScriptStartPath"
Expand Down Expand Up @@ -5423,6 +5435,11 @@ paths:
in: query
schema:
type: boolean
- name: is_not_schedule
description: is not a scheduled job
in: query
schema:
type: boolean
responses:
"200":
description: All jobs
Expand Down Expand Up @@ -8032,6 +8049,12 @@ components:
in: query
schema:
type: string
Label:
name: label
description: mask to filter exact matching job's label (job labels are completed jobs with as a result an object containing a string at key 'wm_label')
in: query
schema:
type: string
ParentJob:
name: parent_job
description:
Expand Down
8 changes: 8 additions & 0 deletions backend/windmill-api/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ impl Migrate for CustomMigrator {
migration.version,
migration.description
);
if migration.version == 20240422144808 {
tracing::info!(
"Special migration to add index concurrently on completed_job labels"
);
sqlx::query!(
"CREATE INDEX CONCURRENTLY labeled_jobs_on_completed_jobs ON completed_job USING GIN ((result -> 'wm_label')) WHERE result ? 'wm_label';"
).execute(&mut *self.inner).await?;
}
let r = self.inner.apply(migration).await;
tracing::info!("Finished applying migration {}", migration.version);
r
Expand Down
26 changes: 25 additions & 1 deletion backend/windmill-api/src/jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ fn generate_get_job_query(no_logs: bool, table: &str) -> String {
result,
deleted,
is_skipped,
result->>'wm_label' as label,
CASE WHEN result is null or pg_column_size(result) < 2000000 THEN result ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as result"
} else {
"scheduled_for,
Expand Down Expand Up @@ -779,6 +780,8 @@ pub struct ListableCompletedJob {
pub tag: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}

#[derive(Deserialize, Clone)]
Expand Down Expand Up @@ -839,6 +842,7 @@ pub struct ListQueueQuery {
pub all_workspaces: Option<bool>,
pub is_flow_step: Option<bool>,
pub has_null_parent: Option<bool>,
pub is_not_schedule: Option<bool>,
}

fn list_queue_jobs_query(w_id: &str, lq: &ListQueueQuery, fields: &[&str]) -> SqlBuilder {
Expand Down Expand Up @@ -943,6 +947,10 @@ fn list_queue_jobs_query(w_id: &str, lq: &ListQueueQuery, fields: &[&str]) -> Sq
sqlb.and_where_le("scheduled_for", "now()");
}

if lq.is_not_schedule.unwrap_or(false) {
sqlb.and_where("schedule_path IS null");
}

sqlb
}

Expand Down Expand Up @@ -1171,13 +1179,14 @@ async fn list_jobs(
"null as concurrent_limit",
"null as concurrency_time_window_s",
"priority",
"result->>'wm_label' as label",
],
))
} else {
None
};

let sql = if lq.success.is_none() {
let sql = if lq.success.is_none() && lq.label.is_none() {
let sqlq = list_queue_jobs_query(
&w_id,
&ListQueueQuery {
Expand All @@ -1203,6 +1212,7 @@ async fn list_jobs(
all_workspaces: lq.all_workspaces,
is_flow_step: lq.is_flow_step,
has_null_parent: lq.has_null_parent,
is_not_schedule: lq.is_not_schedule,
},
&[
"'QueuedJob' as typ",
Expand Down Expand Up @@ -1236,6 +1246,7 @@ async fn list_jobs(
"concurrent_limit",
"concurrency_time_window_s",
"priority",
"null as label",
],
);

Expand Down Expand Up @@ -1968,6 +1979,7 @@ struct UnifiedJob {
concurrent_limit: Option<i32>,
concurrency_time_window_s: Option<i32>,
priority: Option<i16>,
label: Option<String>,
}

impl<'a> From<UnifiedJob> for Job {
Expand Down Expand Up @@ -2005,6 +2017,7 @@ impl<'a> From<UnifiedJob> for Job {
mem_peak: uj.mem_peak,
tag: uj.tag,
priority: uj.priority,
label: uj.label,
}),
"QueuedJob" => Job::QueuedJob(QueuedJob {
workspace_id: uj.workspace_id,
Expand Down Expand Up @@ -3732,6 +3745,14 @@ fn list_completed_jobs_query(
sqlb.and_where("result @> ?".bind(&result.replace("'", "''")));
}

if let Some(label) = &lq.label {
sqlb.and_where("result->>'wm_label' = ?".bind(label));
}

if lq.is_not_schedule.unwrap_or(false) {
sqlb.and_where("schedule_path IS null");
}

sqlb
}
#[derive(Deserialize, Clone)]
Expand Down Expand Up @@ -3763,6 +3784,8 @@ pub struct ListCompletedQuery {
pub scheduled_for_before_now: Option<bool>,
pub all_workspaces: Option<bool>,
pub has_null_parent: Option<bool>,
pub label: Option<String>,
pub is_not_schedule: Option<bool>,
}

async fn list_completed_jobs(
Expand Down Expand Up @@ -3810,6 +3833,7 @@ async fn list_completed_jobs(
"mem_peak",
"tag",
"priority",
"result->>'wm_label' as label",
"'CompletedJob' as type",
],
)
Expand Down
2 changes: 2 additions & 0 deletions backend/windmill-common/src/jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ pub struct CompletedJob {
pub tag: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub label: Option<String>,
}

impl CompletedJob {
Expand Down
22 changes: 6 additions & 16 deletions frontend/src/lib/components/runs/JobLoader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
import { workspaceStore } from '$lib/stores'
import { tweened, type Tweened } from 'svelte/motion'
import { forLater } from '$lib/forLater'
export let jobs: Job[] | undefined
export let user: string | null
export let label: string | null
export let folder: string | null
export let path: string | null
export let success: 'success' | 'failure' | 'running' | undefined = undefined
export let isSkipped: boolean = false
export let hideSchedules: boolean = false
export let showSchedules: boolean = false
export let argFilter: string | undefined
export let resultFilter: string | undefined = undefined
export let schedulePath: string | undefined = undefined
Expand All @@ -39,12 +39,13 @@
$: jobKinds = computeJobKinds(jobKindsCat)
$: ($workspaceStore && loadJobsIntern(true)) ||
(path &&
label &&
success &&
isSkipped != undefined &&
jobKinds &&
user &&
folder &&
hideSchedules != undefined &&
showSchedules != undefined &&
allWorkspaces != undefined &&
argFilter != undefined &&
resultFilter != undefined)
Expand Down Expand Up @@ -107,6 +108,8 @@
running: success == 'running' ? true : undefined,
isSkipped: isSkipped ? undefined : false,
isFlowStep: jobKindsCat != 'all' ? false : undefined,
label: label === null || label === '' ? undefined : label,
isNotSchedule: showSchedules == false ? true : undefined,
args:
argFilter && argFilter != '{}' && argFilter != '' && argError == '' ? argFilter : undefined,
result:
Expand Down Expand Up @@ -141,12 +144,6 @@
try {
jobs = await fetchJobs(maxTs, minTs)
computeCompletedJobs()
if (hideSchedules && !schedulePath) {
jobs = jobs.filter(
(job) => !(job && 'running' in job && job.scheduled_for && forLater(job.scheduled_for))
)
}
} catch (err) {
sendUserToast(`There was a problem fetching jobs: ${err}`, true)
console.error(JSON.stringify(err))
Expand Down Expand Up @@ -215,13 +212,6 @@
.forEach((x) => (jobs![jobs?.findIndex((y) => y.id == x.id)!] = x))
jobs = jobs
computeCompletedJobs()
if (hideSchedules && !schedulePath) {
jobs = jobs.filter(
(job) =>
!(job && 'running' in job && job.scheduled_for && forLater(job.scheduled_for))
)
}
}
loading = false
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/lib/components/runs/RunRow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
export let job: Job
export let selectedId: string | undefined = undefined
export let containerWidth: number = 0
export let containsLabel: boolean = false
let scheduleEditor: ScheduleEditor
</script>
Expand Down Expand Up @@ -170,6 +171,24 @@
{/if}
{/if}
</div>
{#if containsLabel}
<div class="w-3/12 flex justify-start">
{#if job && job?.['label']}
<div class="flex flex-row items-center gap-1">
<div class="text-xs">{job?.['label']}</div>
<Button
size="xs2"
color="light"
on:click={() => {
dispatch('filterByLabel', job?.['label'])
}}
>
<ListFilter size={10} />
</Button>
</div>
{/if}
</div>
{/if}
<div class="w-3/12 flex justify-start">
{#if job && job.schedule_path}
<div class="flex flex-row items-center gap-1">
Expand Down
Loading

0 comments on commit 7d557c2

Please sign in to comment.