Skip to content

Commit 62f14d1

Browse files
committed
feat: add wildcards filter for worker/label/tags
1 parent 3507925 commit 62f14d1

File tree

6 files changed

+119
-30
lines changed

6 files changed

+119
-30
lines changed

backend/windmill-api/openapi.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6786,6 +6786,7 @@ paths:
67866786
- $ref: "#/components/parameters/Running"
67876787
- $ref: "#/components/parameters/ArgsFilter"
67886788
- $ref: "#/components/parameters/ResultFilter"
6789+
- $ref: "#/components/parameters/AllowWildcards"
67896790
- $ref: "#/components/parameters/Tag"
67906791
- $ref: "#/components/parameters/Page"
67916792
- $ref: "#/components/parameters/PerPage"
@@ -6914,6 +6915,7 @@ paths:
69146915
- $ref: "#/components/parameters/Running"
69156916
- $ref: "#/components/parameters/ArgsFilter"
69166917
- $ref: "#/components/parameters/ResultFilter"
6918+
- $ref: "#/components/parameters/AllowWildcards"
69176919
- $ref: "#/components/parameters/Tag"
69186920
- $ref: "#/components/parameters/Page"
69196921
- $ref: "#/components/parameters/PerPage"
@@ -6992,6 +6994,7 @@ paths:
69926994
- $ref: "#/components/parameters/JobKinds"
69936995
- $ref: "#/components/parameters/ArgsFilter"
69946996
- $ref: "#/components/parameters/ResultFilter"
6997+
- $ref: "#/components/parameters/AllowWildcards"
69956998
- $ref: "#/components/parameters/Tag"
69966999
- $ref: "#/components/parameters/Page"
69977000
- $ref: "#/components/parameters/PerPage"
@@ -7055,6 +7058,7 @@ paths:
70557058
- $ref: "#/components/parameters/ArgsFilter"
70567059
- $ref: "#/components/parameters/Tag"
70577060
- $ref: "#/components/parameters/ResultFilter"
7061+
- $ref: "#/components/parameters/AllowWildcards"
70587062
- $ref: "#/components/parameters/Page"
70597063
- $ref: "#/components/parameters/PerPage"
70607064
- name: is_skipped
@@ -11888,6 +11892,7 @@ paths:
1188811892
- $ref: "#/components/parameters/ArgsFilter"
1188911893
- $ref: "#/components/parameters/Tag"
1189011894
- $ref: "#/components/parameters/ResultFilter"
11895+
- $ref: "#/components/parameters/AllowWildcards"
1189111896
- $ref: "#/components/parameters/Page"
1189211897
- $ref: "#/components/parameters/PerPage"
1189311898
- name: is_skipped
@@ -12393,6 +12398,12 @@ components:
1239312398
in: query
1239412399
schema:
1239512400
type: boolean
12401+
AllowWildcards:
12402+
name: allow_wildcards
12403+
description: allow wildcards (*) in the filter of label, tag, worker
12404+
in: query
12405+
schema:
12406+
type: boolean
1239612407
ArgsFilter:
1239712408
name: args
1239812409
description: filter on jobs containing those args as a json subset (@> in postgres)

backend/windmill-api/src/concurrency_groups.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ async fn get_concurrent_intervals(
215215
is_flow_step: _,
216216
all_workspaces: _,
217217
concurrency_key: Some(_),
218+
allow_wildcards: None,
218219
} => true,
219220
_ => false,
220221
};

backend/windmill-api/src/jobs.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,7 @@ pub struct ListQueueQuery {
13741374
pub has_null_parent: Option<bool>,
13751375
pub is_not_schedule: Option<bool>,
13761376
pub concurrency_key: Option<String>,
1377+
pub allow_wildcards: Option<bool>,
13771378
}
13781379

13791380
impl From<ListCompletedQuery> for ListQueueQuery {
@@ -1404,6 +1405,7 @@ impl From<ListCompletedQuery> for ListQueueQuery {
14041405
has_null_parent: lcq.has_null_parent,
14051406
is_not_schedule: lcq.is_not_schedule,
14061407
concurrency_key: lcq.concurrency_key,
1408+
allow_wildcards: lcq.allow_wildcards,
14071409
}
14081410
}
14091411
}
@@ -1427,7 +1429,11 @@ pub fn filter_list_queue_query(
14271429
}
14281430

14291431
if let Some(w) = &lq.worker {
1430-
sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w));
1432+
if lq.allow_wildcards.unwrap_or(false) {
1433+
sqlb.and_where_like_left("v2_job_queue.worker", w.replace("*", "%"));
1434+
} else {
1435+
sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w));
1436+
}
14311437
}
14321438

14331439
if let Some(ps) = &lq.script_path_start {
@@ -1447,8 +1453,13 @@ pub fn filter_list_queue_query(
14471453
sqlb.and_where_eq("created_by", "?".bind(cb));
14481454
}
14491455
if let Some(t) = &lq.tag {
1450-
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
1456+
if lq.allow_wildcards.unwrap_or(false) {
1457+
sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%"));
1458+
} else {
1459+
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
1460+
}
14511461
}
1462+
14521463
if let Some(r) = &lq.running {
14531464
sqlb.and_where_eq("running", &r);
14541465
}
@@ -5446,14 +5457,27 @@ pub fn filter_list_completed_query(
54465457
}
54475458

54485459
if let Some(label) = &lq.label {
5449-
let mut wh = format!("result->'wm_labels' ? ");
5450-
wh.push_str(&format!("'{}'", &label.replace("'", "''")));
5451-
sqlb.and_where("result ? 'wm_labels'");
5452-
sqlb.and_where(&wh);
5460+
if lq.allow_wildcards.unwrap_or(false) {
5461+
let wh = format!(
5462+
"EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') label WHERE label LIKE '{}')",
5463+
&label.replace("*", "%").replace("'", "''")
5464+
);
5465+
sqlb.and_where("result ? 'wm_labels'");
5466+
sqlb.and_where(&wh);
5467+
} else {
5468+
let mut wh = format!("result->'wm_labels' ? ");
5469+
wh.push_str(&format!("'{}'", &label.replace("'", "''")));
5470+
sqlb.and_where("result ? 'wm_labels'");
5471+
sqlb.and_where(&wh);
5472+
}
54535473
}
54545474

54555475
if let Some(worker) = &lq.worker {
5456-
sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker));
5476+
if lq.allow_wildcards.unwrap_or(false) {
5477+
sqlb.and_where_like_left("v2_job_completed.worker", worker.replace("*", "%"));
5478+
} else {
5479+
sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker));
5480+
}
54575481
}
54585482

54595483
if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) {
@@ -5475,8 +5499,13 @@ pub fn filter_list_completed_query(
54755499
sqlb.and_where_eq("runnable_id", "?".bind(h));
54765500
}
54775501
if let Some(t) = &lq.tag {
5478-
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
5502+
if lq.allow_wildcards.unwrap_or(false) {
5503+
sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%"));
5504+
} else {
5505+
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
5506+
}
54795507
}
5508+
54805509
if let Some(cb) = &lq.created_by {
54815510
sqlb.and_where_eq("created_by", "?".bind(cb));
54825511
}
@@ -5618,6 +5647,7 @@ pub struct ListCompletedQuery {
56185647
pub is_not_schedule: Option<bool>,
56195648
pub concurrency_key: Option<String>,
56205649
pub worker: Option<String>,
5650+
pub allow_wildcards: Option<bool>,
56215651
}
56225652

56235653
async fn list_completed_jobs(

frontend/src/lib/components/runs/JobLoader.svelte

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
| undefined
5454
export let lookback: number = 0
5555
export let perPage: number | undefined = undefined
56-
56+
export let allowWildcards: boolean = false
5757
let intervalId: NodeJS.Timeout | undefined
5858
let sync = true
5959
@@ -70,6 +70,7 @@
7070
lookback &&
7171
user &&
7272
folder &&
73+
allowWildcards &&
7374
schedulePath != undefined &&
7475
showFutureJobs != undefined &&
7576
showSchedules != undefined &&
@@ -168,8 +169,8 @@
168169
success == 'running' || success == 'suspended'
169170
? true
170171
: success == 'waiting'
171-
? false
172-
: undefined,
172+
? false
173+
: undefined,
173174
isSkipped: isSkipped ? undefined : false,
174175
// isFlowStep: jobKindsCat != 'all' ? false : undefined,
175176
hasNullParent: jobKindsCat != 'all' ? true : undefined,
@@ -191,7 +192,8 @@
191192
? resultFilter
192193
: undefined,
193194
allWorkspaces: allWorkspaces ? true : undefined,
194-
perPage
195+
perPage,
196+
allowWildcards
195197
})
196198
} catch (e) {
197199
sendUserToast('There was an issue loading jobs, see browser console for more details', true)
@@ -239,7 +241,8 @@
239241
? resultFilter
240242
: undefined,
241243
allWorkspaces: allWorkspaces ? true : undefined,
242-
perPage
244+
perPage,
245+
allowWildcards
243246
})
244247
} catch (e) {
245248
sendUserToast('There was an issue loading jobs, see browser console for more details', true)
@@ -306,8 +309,8 @@
306309
x.started_at
307310
? new Date(x.started_at) > minDate
308311
: x.created_at
309-
? new Date(x.created_at) > minDate
310-
: false
312+
? new Date(x.created_at) > minDate
313+
: false
311314
)
312315
externalJobs = computeExternalJobs(
313316
newExternalJobs.filter((x) => x.started_at && new Date(x.started_at) > minDate)
@@ -440,8 +443,8 @@
440443
x.started_at
441444
? new Date(x.started_at) > minDate
442445
: x.created_at
443-
? new Date(x.created_at) > minDate
444-
: false
446+
? new Date(x.created_at) > minDate
447+
: false
445448
)
446449
} else {
447450
return jobs
@@ -482,7 +485,7 @@
482485
tag: '-',
483486
job_kind: 'script',
484487
duration_ms: x.duration_ms
485-
} as Job)
488+
}) as Job
486489
)
487490
}
488491

frontend/src/lib/components/runs/RunsFilter.svelte

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
export let folder: string | null = null
4747
export let mobile: boolean = false
4848
export let schedulePath: string | undefined
49-
49+
export let allowWildcards: boolean = false
5050
// Autocomplete data
5151
export let paths: string[] = []
5252
export let usernames: string[] = []
@@ -312,6 +312,13 @@
312312
}, 1000)
313313
}}
314314
/>
315+
<div class="absolute top-10">
316+
<Toggle
317+
bind:checked={allowWildcards}
318+
size="xs"
319+
options={{ right: 'allow wildcards (*)' }}
320+
></Toggle>
321+
</div>
315322
</div>
316323
{/key}
317324
{:else if filterBy === 'concurrencyKey'}
@@ -388,6 +395,13 @@
388395
}, 1000)
389396
}}
390397
/>
398+
<div class="absolute top-10">
399+
<Toggle
400+
bind:checked={allowWildcards}
401+
size="xs"
402+
options={{ right: 'allow wildcards (*)' }}
403+
></Toggle>
404+
</div>
391405
</div>
392406
{/key}
393407
{:else if filterBy === 'schedulePath'}
@@ -456,6 +470,13 @@
456470
}, 1000)
457471
}}
458472
/>
473+
<div class="absolute top-10">
474+
<Toggle
475+
bind:checked={allowWildcards}
476+
size="xs"
477+
options={{ right: 'allow wildcards (*)' }}
478+
></Toggle>
479+
</div>
459480
</div>
460481
{/key}
461482
{/if}
@@ -826,6 +847,13 @@
826847
{/key}
827848
{/if}
828849

850+
{#if filterBy === 'tag' || filterBy === 'label' || filterBy === 'worker'}
851+
<Toggle
852+
bind:checked={allowWildcards}
853+
size="xs"
854+
options={{ right: 'allow wildcards (*)' }}
855+
></Toggle>
856+
{/if}
829857
<Label label="Kind">
830858
<ToggleButtonGroup bind:selected={jobKindsCat} let:item>
831859
<ToggleButton value="all" label="All" {item} />

0 commit comments

Comments
 (0)