From 0be55ae98cd0ef48bb3243c470a53e3305420662 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 24 Apr 2024 11:32:25 +0200 Subject: [PATCH] feat: support multiple labels for jobs (wm_label -> wm_labels) --- ...557de9cef7017dcfbcd40370b849a288c52e3.json | 12 +++++++ ...e6169edb0b3a56cb50e03f9df4df511ff1b67.json | 12 ------- ...546c5ff061bd9ed63798024306456ca148aec.json | 12 +++++++ .../20240424083501_add_labels_2.down.sql | 1 + .../20240424083501_add_labels_2.up.sql | 1 + backend/tests/worker.rs | 2 +- backend/windmill-api/openapi.yaml | 6 +++- backend/windmill-api/src/db.rs | 11 +++--- backend/windmill-api/src/jobs.rs | 22 ++++++------ backend/windmill-common/src/jobs.rs | 2 +- .../src/lib/components/runs/RunRow.svelte | 34 ++++++++++++------- .../src/lib/components/runs/RunsFilter.svelte | 2 +- .../src/lib/components/runs/RunsTable.svelte | 4 ++- .../(logged)/runs/[...path]/+page.svelte | 2 ++ 14 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 backend/.sqlx/query-6f12be65a4fe3eb39292164363f557de9cef7017dcfbcd40370b849a288c52e3.json delete mode 100644 backend/.sqlx/query-8199fa82078d7fb8396f21a3f58e6169edb0b3a56cb50e03f9df4df511ff1b67.json create mode 100644 backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json create mode 100644 backend/migrations/20240424083501_add_labels_2.down.sql create mode 100644 backend/migrations/20240424083501_add_labels_2.up.sql diff --git a/backend/.sqlx/query-6f12be65a4fe3eb39292164363f557de9cef7017dcfbcd40370b849a288c52e3.json b/backend/.sqlx/query-6f12be65a4fe3eb39292164363f557de9cef7017dcfbcd40370b849a288c52e3.json new file mode 100644 index 0000000000..fb92042662 --- /dev/null +++ b/backend/.sqlx/query-6f12be65a4fe3eb39292164363f557de9cef7017dcfbcd40370b849a288c52e3.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "6f12be65a4fe3eb39292164363f557de9cef7017dcfbcd40370b849a288c52e3" +} diff --git a/backend/.sqlx/query-8199fa82078d7fb8396f21a3f58e6169edb0b3a56cb50e03f9df4df511ff1b67.json b/backend/.sqlx/query-8199fa82078d7fb8396f21a3f58e6169edb0b3a56cb50e03f9df4df511ff1b67.json deleted file mode 100644 index 12c079ecf5..0000000000 --- a/backend/.sqlx/query-8199fa82078d7fb8396f21a3f58e6169edb0b3a56cb50e03f9df4df511ff1b67.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "CREATE INDEX CONCURRENTLY labeled_jobs_on_completed_jobs ON completed_job USING GIN ((result -> 'wm_label')) WHERE result ? 'wm_label';", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "8199fa82078d7fb8396f21a3f58e6169edb0b3a56cb50e03f9df4df511ff1b67" -} diff --git a/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json b/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json new file mode 100644 index 0000000000..1f40dbca3b --- /dev/null +++ b/backend/.sqlx/query-89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_label';", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "89e72f997e27b9298bd923e7f2b546c5ff061bd9ed63798024306456ca148aec" +} diff --git a/backend/migrations/20240424083501_add_labels_2.down.sql b/backend/migrations/20240424083501_add_labels_2.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20240424083501_add_labels_2.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20240424083501_add_labels_2.up.sql b/backend/migrations/20240424083501_add_labels_2.up.sql new file mode 100644 index 0000000000..0da0a538a3 --- /dev/null +++ b/backend/migrations/20240424083501_add_labels_2.up.sql @@ -0,0 +1 @@ +-- Add up migration script here diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 924bd5d89f..ded754af14 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -1026,7 +1026,7 @@ async fn listen_for_uuid_on( async fn completed_job(uuid: Uuid, db: &Pool) -> CompletedJob { - sqlx::query_as::<_, CompletedJob>("SELECT *, result->>'wm_label' as label FROM completed_job WHERE id = $1").bind(uuid) + sqlx::query_as::<_, CompletedJob>("SELECT *, result->'wm_labels' as label FROM completed_job WHERE id = $1").bind(uuid) .fetch_one(db) .await .unwrap() diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 2f6fc6d80c..b08839222d 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -8051,7 +8051,7 @@ components: 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') + description: mask to filter exact matching job's label (job labels are completed jobs with as a result an object containing a string in the array at key 'wm_labels') in: query schema: type: string @@ -8780,6 +8780,10 @@ components: type: string priority: type: integer + labels: + type: array + items: + type: string required: - id - created_by diff --git a/backend/windmill-api/src/db.rs b/backend/windmill-api/src/db.rs index f6fa96ba6b..a854be7d37 100644 --- a/backend/windmill-api/src/db.rs +++ b/backend/windmill-api/src/db.rs @@ -136,12 +136,13 @@ impl Migrate for CustomMigrator { migration.version, migration.description ); - if migration.version == 20240422144808 { - tracing::info!( - "Special migration to add index concurrently on completed_job labels" - ); + if migration.version == 20240424083501 { + tracing::info!("Special migration to add index concurrently on job labels 2"); sqlx::query!( - "CREATE INDEX CONCURRENTLY labeled_jobs_on_completed_jobs ON completed_job USING GIN ((result -> 'wm_label')) WHERE result ? 'wm_label';" + "DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs" + ).execute(&mut *self.inner).await?; + sqlx::query!( + "CREATE INDEX CONCURRENTLY labeled_jobs_on_jobs ON completed_job USING GIN ((result -> 'wm_labels')) WHERE result ? 'wm_label';" ).execute(&mut *self.inner).await?; } let r = self.inner.apply(migration).await; diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index d4607e2a4e..7d2d114278 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -585,7 +585,7 @@ fn generate_get_job_query(no_logs: bool, table: &str) -> String { result, deleted, is_skipped, - result->>'wm_label' as label, + result->'wm_labels' as labels, CASE WHEN result is null or pg_column_size(result) < 2000000 THEN result ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as result" } else { "scheduled_for, @@ -781,7 +781,7 @@ pub struct ListableCompletedJob { #[serde(skip_serializing_if = "Option::is_none")] pub priority: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub label: Option, + pub labels: Option, } #[derive(Deserialize, Clone)] @@ -1179,7 +1179,7 @@ async fn list_jobs( "null as concurrent_limit", "null as concurrency_time_window_s", "priority", - "result->>'wm_label' as label", + "result->'wm_labels' as labels", ], )) } else { @@ -1246,7 +1246,7 @@ async fn list_jobs( "concurrent_limit", "concurrency_time_window_s", "priority", - "null as label", + "null as labels", ], ); @@ -1979,7 +1979,7 @@ struct UnifiedJob { concurrent_limit: Option, concurrency_time_window_s: Option, priority: Option, - label: Option, + labels: Option, } impl<'a> From for Job { @@ -2017,7 +2017,7 @@ impl<'a> From for Job { mem_peak: uj.mem_peak, tag: uj.tag, priority: uj.priority, - label: uj.label, + labels: uj.labels, }), "QueuedJob" => Job::QueuedJob(QueuedJob { workspace_id: uj.workspace_id, @@ -2298,7 +2298,7 @@ pub async fn restart_flow( check_license_key_valid().await?; let completed_job = sqlx::query_as::<_, CompletedJob>( - "SELECT *, result->>'wm_label' as label from completed_job WHERE id = $1 and workspace_id = $2", + "SELECT *, result->'wm_labels' as labels from completed_job WHERE id = $1 and workspace_id = $2", ) .bind(job_id) .bind(&w_id) @@ -3746,8 +3746,10 @@ fn list_completed_jobs_query( } if let Some(label) = &lq.label { - sqlb.and_where("result->>'wm_label' = ?".bind(label)); - sqlb.and_where("result ? 'wm_label'"); + let mut wh = format!("result->'wm_labels' ? "); + wh.push_str(&format!("'{}'", &label.replace("'", "''"))); + sqlb.and_where(&wh); + sqlb.and_where("result ? 'wm_labels'"); } if lq.is_not_schedule.unwrap_or(false) { @@ -3834,7 +3836,7 @@ async fn list_completed_jobs( "mem_peak", "tag", "priority", - "result->>'wm_label' as label", + "result->'wm_labels' as labels", "'CompletedJob' as type", ], ) diff --git a/backend/windmill-common/src/jobs.rs b/backend/windmill-common/src/jobs.rs index f15f73b2df..f93609385f 100644 --- a/backend/windmill-common/src/jobs.rs +++ b/backend/windmill-common/src/jobs.rs @@ -244,7 +244,7 @@ pub struct CompletedJob { #[serde(skip_serializing_if = "Option::is_none")] pub priority: Option, #[serde(skip_serializing_if = "Option::is_none")] - pub label: Option, + pub labels: Option, } impl CompletedJob { diff --git a/frontend/src/lib/components/runs/RunRow.svelte b/frontend/src/lib/components/runs/RunRow.svelte index 93f95ee3b9..42eaea4dd8 100644 --- a/frontend/src/lib/components/runs/RunRow.svelte +++ b/frontend/src/lib/components/runs/RunRow.svelte @@ -29,6 +29,7 @@ export let selectedId: string | undefined = undefined export let containerWidth: number = 0 export let containsLabel: boolean = false + export let activeLabel: string | null let scheduleEditor: ScheduleEditor @@ -108,7 +109,10 @@
{#if job.script_path}
- + {job.script_path} + {#if Array.isArray(job?.['labels'])} + {#each job?.['labels'] as label} + + {/each} + {/if}
{/if}
diff --git a/frontend/src/lib/components/runs/RunsFilter.svelte b/frontend/src/lib/components/runs/RunsFilter.svelte index 5164310083..79779de78b 100644 --- a/frontend/src/lib/components/runs/RunsFilter.svelte +++ b/frontend/src/lib/components/runs/RunsFilter.svelte @@ -219,7 +219,7 @@ Label Labels are values in the result of completed jobs at key 'wm_label' to easily + >Labels are string values in the array at the result field 'wm_labels' to easily filter them diff --git a/frontend/src/lib/components/runs/RunsTable.svelte b/frontend/src/lib/components/runs/RunsTable.svelte index 20c06c0221..85141402bc 100644 --- a/frontend/src/lib/components/runs/RunsTable.svelte +++ b/frontend/src/lib/components/runs/RunsTable.svelte @@ -8,6 +8,7 @@ export let jobs: Job[] | undefined = undefined export let selectedId: string | undefined = undefined export let selectedWorkspace: string | undefined = undefined + export let activeLabel: string | null = null // const loadMoreQuantity: number = 100 function getTime(job: Job): string | undefined { @@ -22,7 +23,7 @@ let newContainsLabel = false for (const job of jobs) { - if (job?.['label'] != undefined) { + if (job?.['labels'] != undefined) { newContainsLabel = true } const field: string | undefined = getTime(job) @@ -182,6 +183,7 @@ selectedId = jobOrDate.job.id dispatch('select') }} + {activeLabel} on:filterByLabel on:filterByPath on:filterByUser diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte index d6ee5d9d62..9811445636 100644 --- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte @@ -465,6 +465,7 @@ {#if jobs}