mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-25 08:00:59 +00:00
feat: add wildcards filter for worker/label/tags
This commit is contained in:
@@ -6786,6 +6786,7 @@ paths:
|
||||
- $ref: "#/components/parameters/Running"
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
@@ -6914,6 +6915,7 @@ paths:
|
||||
- $ref: "#/components/parameters/Running"
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
@@ -6992,6 +6994,7 @@ paths:
|
||||
- $ref: "#/components/parameters/JobKinds"
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
@@ -7055,6 +7058,7 @@ paths:
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_skipped
|
||||
@@ -11888,6 +11892,7 @@ paths:
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_skipped
|
||||
@@ -12393,6 +12398,12 @@ components:
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
AllowWildcards:
|
||||
name: allow_wildcards
|
||||
description: allow wildcards (*) in the filter of label, tag, worker
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
ArgsFilter:
|
||||
name: args
|
||||
description: filter on jobs containing those args as a json subset (@> in postgres)
|
||||
|
||||
@@ -215,6 +215,7 @@ async fn get_concurrent_intervals(
|
||||
is_flow_step: _,
|
||||
all_workspaces: _,
|
||||
concurrency_key: Some(_),
|
||||
allow_wildcards: None,
|
||||
} => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@@ -1374,6 +1374,7 @@ pub struct ListQueueQuery {
|
||||
pub has_null_parent: Option<bool>,
|
||||
pub is_not_schedule: Option<bool>,
|
||||
pub concurrency_key: Option<String>,
|
||||
pub allow_wildcards: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<ListCompletedQuery> for ListQueueQuery {
|
||||
@@ -1404,6 +1405,7 @@ impl From<ListCompletedQuery> for ListQueueQuery {
|
||||
has_null_parent: lcq.has_null_parent,
|
||||
is_not_schedule: lcq.is_not_schedule,
|
||||
concurrency_key: lcq.concurrency_key,
|
||||
allow_wildcards: lcq.allow_wildcards,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1427,7 +1429,11 @@ pub fn filter_list_queue_query(
|
||||
}
|
||||
|
||||
if let Some(w) = &lq.worker {
|
||||
sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job_queue.worker", w.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ps) = &lq.script_path_start {
|
||||
@@ -1447,8 +1453,13 @@ pub fn filter_list_queue_query(
|
||||
sqlb.and_where_eq("created_by", "?".bind(cb));
|
||||
}
|
||||
if let Some(t) = &lq.tag {
|
||||
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(r) = &lq.running {
|
||||
sqlb.and_where_eq("running", &r);
|
||||
}
|
||||
@@ -5446,14 +5457,27 @@ pub fn filter_list_completed_query(
|
||||
}
|
||||
|
||||
if let Some(label) = &lq.label {
|
||||
let mut wh = format!("result->'wm_labels' ? ");
|
||||
wh.push_str(&format!("'{}'", &label.replace("'", "''")));
|
||||
sqlb.and_where("result ? 'wm_labels'");
|
||||
sqlb.and_where(&wh);
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
let wh = format!(
|
||||
"EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') label WHERE label LIKE '{}')",
|
||||
&label.replace("*", "%").replace("'", "''")
|
||||
);
|
||||
sqlb.and_where("result ? 'wm_labels'");
|
||||
sqlb.and_where(&wh);
|
||||
} else {
|
||||
let mut wh = format!("result->'wm_labels' ? ");
|
||||
wh.push_str(&format!("'{}'", &label.replace("'", "''")));
|
||||
sqlb.and_where("result ? 'wm_labels'");
|
||||
sqlb.and_where(&wh);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(worker) = &lq.worker {
|
||||
sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job_completed.worker", worker.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker));
|
||||
}
|
||||
}
|
||||
|
||||
if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) {
|
||||
@@ -5475,8 +5499,13 @@ pub fn filter_list_completed_query(
|
||||
sqlb.and_where_eq("runnable_id", "?".bind(h));
|
||||
}
|
||||
if let Some(t) = &lq.tag {
|
||||
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cb) = &lq.created_by {
|
||||
sqlb.and_where_eq("created_by", "?".bind(cb));
|
||||
}
|
||||
@@ -5618,6 +5647,7 @@ pub struct ListCompletedQuery {
|
||||
pub is_not_schedule: Option<bool>,
|
||||
pub concurrency_key: Option<String>,
|
||||
pub worker: Option<String>,
|
||||
pub allow_wildcards: Option<bool>,
|
||||
}
|
||||
|
||||
async fn list_completed_jobs(
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
| undefined
|
||||
export let lookback: number = 0
|
||||
export let perPage: number | undefined = undefined
|
||||
|
||||
export let allowWildcards: boolean = false
|
||||
let intervalId: NodeJS.Timeout | undefined
|
||||
let sync = true
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
lookback &&
|
||||
user &&
|
||||
folder &&
|
||||
allowWildcards &&
|
||||
schedulePath != undefined &&
|
||||
showFutureJobs != undefined &&
|
||||
showSchedules != undefined &&
|
||||
@@ -168,8 +169,8 @@
|
||||
success == 'running' || success == 'suspended'
|
||||
? true
|
||||
: success == 'waiting'
|
||||
? false
|
||||
: undefined,
|
||||
? false
|
||||
: undefined,
|
||||
isSkipped: isSkipped ? undefined : false,
|
||||
// isFlowStep: jobKindsCat != 'all' ? false : undefined,
|
||||
hasNullParent: jobKindsCat != 'all' ? true : undefined,
|
||||
@@ -191,7 +192,8 @@
|
||||
? resultFilter
|
||||
: undefined,
|
||||
allWorkspaces: allWorkspaces ? true : undefined,
|
||||
perPage
|
||||
perPage,
|
||||
allowWildcards
|
||||
})
|
||||
} catch (e) {
|
||||
sendUserToast('There was an issue loading jobs, see browser console for more details', true)
|
||||
@@ -239,7 +241,8 @@
|
||||
? resultFilter
|
||||
: undefined,
|
||||
allWorkspaces: allWorkspaces ? true : undefined,
|
||||
perPage
|
||||
perPage,
|
||||
allowWildcards
|
||||
})
|
||||
} catch (e) {
|
||||
sendUserToast('There was an issue loading jobs, see browser console for more details', true)
|
||||
@@ -306,8 +309,8 @@
|
||||
x.started_at
|
||||
? new Date(x.started_at) > minDate
|
||||
: x.created_at
|
||||
? new Date(x.created_at) > minDate
|
||||
: false
|
||||
? new Date(x.created_at) > minDate
|
||||
: false
|
||||
)
|
||||
externalJobs = computeExternalJobs(
|
||||
newExternalJobs.filter((x) => x.started_at && new Date(x.started_at) > minDate)
|
||||
@@ -440,8 +443,8 @@
|
||||
x.started_at
|
||||
? new Date(x.started_at) > minDate
|
||||
: x.created_at
|
||||
? new Date(x.created_at) > minDate
|
||||
: false
|
||||
? new Date(x.created_at) > minDate
|
||||
: false
|
||||
)
|
||||
} else {
|
||||
return jobs
|
||||
@@ -482,7 +485,7 @@
|
||||
tag: '-',
|
||||
job_kind: 'script',
|
||||
duration_ms: x.duration_ms
|
||||
} as Job)
|
||||
}) as Job
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
export let folder: string | null = null
|
||||
export let mobile: boolean = false
|
||||
export let schedulePath: string | undefined
|
||||
|
||||
export let allowWildcards: boolean = false
|
||||
// Autocomplete data
|
||||
export let paths: string[] = []
|
||||
export let usernames: string[] = []
|
||||
@@ -312,6 +312,13 @@
|
||||
}, 1000)
|
||||
}}
|
||||
/>
|
||||
<div class="absolute top-10">
|
||||
<Toggle
|
||||
bind:checked={allowWildcards}
|
||||
size="xs"
|
||||
options={{ right: 'allow wildcards (*)' }}
|
||||
></Toggle>
|
||||
</div>
|
||||
</div>
|
||||
{/key}
|
||||
{:else if filterBy === 'concurrencyKey'}
|
||||
@@ -388,6 +395,13 @@
|
||||
}, 1000)
|
||||
}}
|
||||
/>
|
||||
<div class="absolute top-10">
|
||||
<Toggle
|
||||
bind:checked={allowWildcards}
|
||||
size="xs"
|
||||
options={{ right: 'allow wildcards (*)' }}
|
||||
></Toggle>
|
||||
</div>
|
||||
</div>
|
||||
{/key}
|
||||
{:else if filterBy === 'schedulePath'}
|
||||
@@ -456,6 +470,13 @@
|
||||
}, 1000)
|
||||
}}
|
||||
/>
|
||||
<div class="absolute top-10">
|
||||
<Toggle
|
||||
bind:checked={allowWildcards}
|
||||
size="xs"
|
||||
options={{ right: 'allow wildcards (*)' }}
|
||||
></Toggle>
|
||||
</div>
|
||||
</div>
|
||||
{/key}
|
||||
{/if}
|
||||
@@ -826,6 +847,13 @@
|
||||
{/key}
|
||||
{/if}
|
||||
|
||||
{#if filterBy === 'tag' || filterBy === 'label' || filterBy === 'worker'}
|
||||
<Toggle
|
||||
bind:checked={allowWildcards}
|
||||
size="xs"
|
||||
options={{ right: 'allow wildcards (*)' }}
|
||||
></Toggle>
|
||||
{/if}
|
||||
<Label label="Kind">
|
||||
<ToggleButtonGroup bind:selected={jobKindsCat} let:item>
|
||||
<ToggleButton value="all" label="All" {item} />
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
let user: string | null = $page.url.searchParams.get('user')
|
||||
let folder: string | null = $page.url.searchParams.get('folder')
|
||||
let label: string | null = $page.url.searchParams.get('label')
|
||||
let allowWildcards: boolean = $page.url.searchParams.get('allow_wildcards') == 'true'
|
||||
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
|
||||
@@ -69,14 +70,14 @@
|
||||
$page.url.searchParams.get('show_schedules') != undefined
|
||||
? $page.url.searchParams.get('show_schedules') == 'true'
|
||||
: localStorage.getItem('show_schedules_in_run') == 'false'
|
||||
? false
|
||||
: true
|
||||
? false
|
||||
: true
|
||||
let showFutureJobs: boolean =
|
||||
$page.url.searchParams.get('show_future_jobs') != undefined
|
||||
? $page.url.searchParams.get('show_future_jobs') == 'true'
|
||||
: localStorage.getItem('show_future_jobs') == 'false'
|
||||
? false
|
||||
: true
|
||||
? false
|
||||
: true
|
||||
|
||||
let argFilter: any = $page.url.searchParams.get('arg')
|
||||
? JSON.parse(decodeURIComponent($page.url.searchParams.get('arg') ?? '{}'))
|
||||
@@ -101,6 +102,7 @@
|
||||
concurrencyKey = $page.url.searchParams.get('concurrency_key')
|
||||
tag = $page.url.searchParams.get('tag')
|
||||
worker = $page.url.searchParams.get('worker')
|
||||
allowWildcards = $page.url.searchParams.get('allow_wildcards') == 'true'
|
||||
// Rest of filters handled by RunsFilter
|
||||
success = ($page.url.searchParams.get('success') ?? undefined) as
|
||||
| 'running'
|
||||
@@ -116,14 +118,14 @@
|
||||
$page.url.searchParams.get('show_schedules') != undefined
|
||||
? $page.url.searchParams.get('show_schedules') == 'true'
|
||||
: localStorage.getItem('show_schedules_in_run') == 'false'
|
||||
? false
|
||||
: true
|
||||
? false
|
||||
: true
|
||||
showFutureJobs =
|
||||
$page.url.searchParams.get('show_future_jobs') != undefined
|
||||
? $page.url.searchParams.get('show_future_jobs') == 'true'
|
||||
: localStorage.getItem('show_future_jobs') == 'false'
|
||||
? false
|
||||
: true
|
||||
? false
|
||||
: true
|
||||
|
||||
argFilter = $page.url.searchParams.get('arg')
|
||||
? JSON.parse(decodeURIComponent($page.url.searchParams.get('arg') ?? '{}'))
|
||||
@@ -198,6 +200,7 @@
|
||||
graph ||
|
||||
maxTs ||
|
||||
allWorkspaces ||
|
||||
allowWildcards ||
|
||||
$workspaceStore) &&
|
||||
setQuery(false)
|
||||
|
||||
@@ -307,6 +310,12 @@
|
||||
searchParams.delete('label')
|
||||
}
|
||||
|
||||
if (allowWildcards) {
|
||||
searchParams.set('allow_wildcards', allowWildcards.toString())
|
||||
} else {
|
||||
searchParams.delete('allow_wildcards')
|
||||
}
|
||||
|
||||
if (graph != 'RunChart') {
|
||||
searchParams.set('graph', graph)
|
||||
} else {
|
||||
@@ -411,6 +420,7 @@
|
||||
tag = null
|
||||
schedulePath = undefined
|
||||
worker = null
|
||||
allowWildcards = false
|
||||
}
|
||||
|
||||
function filterByConcurrencyKey(e: CustomEvent<string>) {
|
||||
@@ -433,6 +443,7 @@
|
||||
tag = e.detail
|
||||
schedulePath = undefined
|
||||
worker = null
|
||||
allowWildcards = false
|
||||
}
|
||||
|
||||
function filterBySchedule(e: CustomEvent<string>) {
|
||||
@@ -455,6 +466,7 @@
|
||||
tag = null
|
||||
schedulePath = undefined
|
||||
worker = e.detail
|
||||
allowWildcards = false
|
||||
}
|
||||
|
||||
let calendarChangeTimeout: NodeJS.Timeout | undefined = undefined
|
||||
@@ -499,8 +511,8 @@
|
||||
success == 'running' || success == 'suspended'
|
||||
? true
|
||||
: success == 'waiting'
|
||||
? false
|
||||
: undefined,
|
||||
? false
|
||||
: undefined,
|
||||
isSkipped: isSkipped ? undefined : false,
|
||||
// isFlowStep: jobKindsCat != 'all' ? false : undefined,
|
||||
hasNullParent:
|
||||
@@ -519,7 +531,8 @@
|
||||
resultFilter && resultFilter != '{}' && resultFilter != '' && resultError == ''
|
||||
? resultFilter
|
||||
: undefined,
|
||||
allWorkspaces: allWorkspaces ? true : undefined
|
||||
allWorkspaces: allWorkspaces ? true : undefined,
|
||||
allowWildcards: allowWildcards ? true : undefined
|
||||
}
|
||||
|
||||
selectedFiltersString = JSON.stringify(selectedFilters, null, 4)
|
||||
@@ -577,6 +590,7 @@
|
||||
</script>
|
||||
|
||||
<JobLoader
|
||||
{allowWildcards}
|
||||
{allWorkspaces}
|
||||
bind:jobs
|
||||
{user}
|
||||
@@ -705,6 +719,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<RunsFilter
|
||||
bind:allowWildcards
|
||||
bind:isSkipped
|
||||
bind:user
|
||||
bind:folder
|
||||
@@ -1092,6 +1107,7 @@
|
||||
</Tooltip>
|
||||
</div>
|
||||
<RunsFilter
|
||||
bind:allowWildcards
|
||||
bind:isSkipped
|
||||
{paths}
|
||||
{usernames}
|
||||
|
||||
Reference in New Issue
Block a user