From 5b315bf2c8e3d992ca690f994cea2205541ab5ae Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 27 Oct 2025 15:29:53 +0100 Subject: [PATCH 01/32] fix: improve jobs runs page performance (#6942) --- ...20967ed4a218782192c6c6fc1498f45d753a6.json | 12 -- ...dc4af312fda13d832f9e8b236655628e5b81c.json | 12 ++ ...153c43903f929ae5d62fbba12610f89c36d55.json | 2 +- ...3a6428b3c7cbdef4af70a6660c1a5900d17a6.json | 12 ++ ...5c003bc4e897ee01746d6f17aeee387d1505.json} | 4 +- ...5eb5140c563a2b191714ef9028b56391b794.json} | 4 +- ...073fc77421710992b10f526aa36bc64ff0930.json | 16 --- ...f798240d4fcdd52ce2745532ca30f736d25ca.json | 12 ++ ...aaee032e731db1e6bd49d991a54f49ab8fa46.json | 12 -- ...b85edafb9408d0306f17bb78b65a5d81c570b.json | 12 ++ ...4b83a05f1d649bfedff9f24cc3e6c702d42df.json | 12 ++ backend/windmill-api/openapi.yaml | 109 ++++++++++-------- .../windmill-api/src/concurrency_groups.rs | 10 +- backend/windmill-api/src/jobs.rs | 77 ++++++++----- backend/windmill-api/src/live_migrations.rs | 73 ++++++++---- backend/windmill-api/src/schedule.rs | 2 +- backend/windmill-common/src/jobs.rs | 1 + backend/windmill-queue/src/jobs.rs | 3 +- .../components/FlowHistoryJobPicker.svelte | 65 +++++++---- frontend/src/lib/components/RunChart.svelte | 12 +- .../src/lib/components/SavedInputs.svelte | 73 +++++++----- .../flows/map/FlowModuleSchemaMap.svelte | 2 +- .../src/lib/components/runs/JobsLoader.svelte | 106 +++++++++++------ .../components/runs/ManuelDatePicker.svelte | 27 +++-- .../src/lib/components/runs/RunRow.svelte | 15 ++- .../src/lib/components/runs/RunsTable.svelte | 2 +- .../components/stepHistoryLoader.svelte.ts | 2 +- 27 files changed, 425 insertions(+), 264 deletions(-) delete mode 100644 backend/.sqlx/query-3a5edf3dd884b5a8862bb112f6520967ed4a218782192c6c6fc1498f45d753a6.json create mode 100644 backend/.sqlx/query-3dca0aded0ec744b084359e1a77dc4af312fda13d832f9e8b236655628e5b81c.json create mode 100644 backend/.sqlx/query-5c403799772e1c44bd00e5376893a6428b3c7cbdef4af70a6660c1a5900d17a6.json rename backend/.sqlx/{query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json => query-5d99d2b058d4896f9ac1cea04fa35c003bc4e897ee01746d6f17aeee387d1505.json} (62%) rename backend/.sqlx/{query-430ea56dea72c7d326735952bf85708dcc4811857b7e5631f0decf5d75ef3aa3.json => query-5e6dcb3e7a9bc174a040cfba96555eb5140c563a2b191714ef9028b56391b794.json} (77%) delete mode 100644 backend/.sqlx/query-69550451b86f221a3d2ef626be7073fc77421710992b10f526aa36bc64ff0930.json create mode 100644 backend/.sqlx/query-6ad24aef02d86ea507d232ad0bbf798240d4fcdd52ce2745532ca30f736d25ca.json delete mode 100644 backend/.sqlx/query-931703a98d2ee5fb58d3380896baaee032e731db1e6bd49d991a54f49ab8fa46.json create mode 100644 backend/.sqlx/query-ea9385509319f66b9330221eb50b85edafb9408d0306f17bb78b65a5d81c570b.json create mode 100644 backend/.sqlx/query-f17c9fed09897191ee70214223d4b83a05f1d649bfedff9f24cc3e6c702d42df.json diff --git a/backend/.sqlx/query-3a5edf3dd884b5a8862bb112f6520967ed4a218782192c6c6fc1498f45d753a6.json b/backend/.sqlx/query-3a5edf3dd884b5a8862bb112f6520967ed4a218782192c6c6fc1498f45d753a6.json deleted file mode 100644 index 26d0b63b5c..0000000000 --- a/backend/.sqlx/query-3a5edf3dd884b5a8862bb112f6520967ed4a218782192c6c6fc1498f45d753a6.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "create index concurrently if not exists ix_job_created_at ON v2_job (created_at DESC)", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "3a5edf3dd884b5a8862bb112f6520967ed4a218782192c6c6fc1498f45d753a6" -} diff --git a/backend/.sqlx/query-3dca0aded0ec744b084359e1a77dc4af312fda13d832f9e8b236655628e5b81c.json b/backend/.sqlx/query-3dca0aded0ec744b084359e1a77dc4af312fda13d832f9e8b236655628e5b81c.json new file mode 100644 index 0000000000..2488154bbd --- /dev/null +++ b/backend/.sqlx/query-3dca0aded0ec744b084359e1a77dc4af312fda13d832f9e8b236655628e5b81c.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_started_at_new_2", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "3dca0aded0ec744b084359e1a77dc4af312fda13d832f9e8b236655628e5b81c" +} diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 36ddb8ab9f..713ccb9dd3 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - true + null ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/.sqlx/query-5c403799772e1c44bd00e5376893a6428b3c7cbdef4af70a6660c1a5900d17a6.json b/backend/.sqlx/query-5c403799772e1c44bd00e5376893a6428b3c7cbdef4af70a6660c1a5900d17a6.json new file mode 100644 index 0000000000..5dc78dab56 --- /dev/null +++ b/backend/.sqlx/query-5c403799772e1c44bd00e5376893a6428b3c7cbdef4af70a6660c1a5900d17a6.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "create index concurrently if not exists ix_job_workspace_id_completed_at_all ON v2_job_completed (workspace_id, completed_at DESC)", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "5c403799772e1c44bd00e5376893a6428b3c7cbdef4af70a6660c1a5900d17a6" +} diff --git a/backend/.sqlx/query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json b/backend/.sqlx/query-5d99d2b058d4896f9ac1cea04fa35c003bc4e897ee01746d6f17aeee387d1505.json similarity index 62% rename from backend/.sqlx/query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json rename to backend/.sqlx/query-5d99d2b058d4896f9ac1cea04fa35c003bc4e897ee01746d6f17aeee387d1505.json index 72169ec94b..c22e4bc5cf 100644 --- a/backend/.sqlx/query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json +++ b/backend/.sqlx/query-5d99d2b058d4896f9ac1cea04fa35c003bc4e897ee01746d6f17aeee387d1505.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlescriptflow') AND parent_job IS NULL", + "query": "create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlestepflow') AND parent_job IS NULL", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0" + "hash": "5d99d2b058d4896f9ac1cea04fa35c003bc4e897ee01746d6f17aeee387d1505" } diff --git a/backend/.sqlx/query-430ea56dea72c7d326735952bf85708dcc4811857b7e5631f0decf5d75ef3aa3.json b/backend/.sqlx/query-5e6dcb3e7a9bc174a040cfba96555eb5140c563a2b191714ef9028b56391b794.json similarity index 77% rename from backend/.sqlx/query-430ea56dea72c7d326735952bf85708dcc4811857b7e5631f0decf5d75ef3aa3.json rename to backend/.sqlx/query-5e6dcb3e7a9bc174a040cfba96555eb5140c563a2b191714ef9028b56391b794.json index 660b5cb402..5863dc5f98 100644 --- a/backend/.sqlx/query-430ea56dea72c7d326735952bf85708dcc4811857b7e5631f0decf5d75ef3aa3.json +++ b/backend/.sqlx/query-5e6dcb3e7a9bc174a040cfba96555eb5140c563a2b191714ef9028b56391b794.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n schedule.path, t.jobs FROM schedule,\n LATERAL(SELECT ARRAY(\n SELECT json_build_object('id', id, 'success', status = 'success', 'duration_ms', duration_ms)\n FROM v2_job_completed c JOIN v2_job j USING (id)\n WHERE trigger_kind = 'schedule'\n AND trigger = schedule.path\n AND c.workspace_id = $1\n AND j.workspace_id = $1\n AND parent_job IS NULL AND runnable_path = schedule.script_path\n AND status <> 'skipped'\n ORDER BY created_at DESC\n LIMIT 20\n ) AS jobs) t\n WHERE workspace_id = $1\n ORDER BY edited_at DESC\n LIMIT $2 OFFSET $3", + "query": "SELECT\n schedule.path, t.jobs FROM schedule,\n LATERAL(SELECT ARRAY(\n SELECT json_build_object('id', id, 'success', status = 'success', 'duration_ms', duration_ms)\n FROM v2_job_completed c JOIN v2_job j USING (id)\n WHERE trigger_kind = 'schedule'\n AND trigger = schedule.path\n AND c.workspace_id = $1\n AND j.workspace_id = $1\n AND parent_job IS NULL AND runnable_path = schedule.script_path\n AND status <> 'skipped'\n ORDER BY completed_at DESC\n LIMIT 20\n ) AS jobs) t\n WHERE workspace_id = $1\n ORDER BY edited_at DESC\n LIMIT $2 OFFSET $3", "describe": { "columns": [ { @@ -26,5 +26,5 @@ null ] }, - "hash": "430ea56dea72c7d326735952bf85708dcc4811857b7e5631f0decf5d75ef3aa3" + "hash": "5e6dcb3e7a9bc174a040cfba96555eb5140c563a2b191714ef9028b56391b794" } diff --git a/backend/.sqlx/query-69550451b86f221a3d2ef626be7073fc77421710992b10f526aa36bc64ff0930.json b/backend/.sqlx/query-69550451b86f221a3d2ef626be7073fc77421710992b10f526aa36bc64ff0930.json deleted file mode 100644 index caf6213fa2..0000000000 --- a/backend/.sqlx/query-69550451b86f221a3d2ef626be7073fc77421710992b10f526aa36bc64ff0930.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO script\n (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets)\n\n SELECT workspace_id, $1, path, array_prepend($2::bigint, COALESCE(parent_hashes, '{}'::bigint[])), summary, description, content, created_by, schema, is_template, extra_perms, NULL, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int8", - "Text" - ] - }, - "nullable": [] - }, - "hash": "69550451b86f221a3d2ef626be7073fc77421710992b10f526aa36bc64ff0930" -} diff --git a/backend/.sqlx/query-6ad24aef02d86ea507d232ad0bbf798240d4fcdd52ce2745532ca30f736d25ca.json b/backend/.sqlx/query-6ad24aef02d86ea507d232ad0bbf798240d4fcdd52ce2745532ca30f736d25ca.json new file mode 100644 index 0000000000..bf127e8cca --- /dev/null +++ b/backend/.sqlx/query-6ad24aef02d86ea507d232ad0bbf798240d4fcdd52ce2745532ca30f736d25ca.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS ix_job_created_at", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "6ad24aef02d86ea507d232ad0bbf798240d4fcdd52ce2745532ca30f736d25ca" +} diff --git a/backend/.sqlx/query-931703a98d2ee5fb58d3380896baaee032e731db1e6bd49d991a54f49ab8fa46.json b/backend/.sqlx/query-931703a98d2ee5fb58d3380896baaee032e731db1e6bd49d991a54f49ab8fa46.json deleted file mode 100644 index 5f86a45011..0000000000 --- a/backend/.sqlx/query-931703a98d2ee5fb58d3380896baaee032e731db1e6bd49d991a54f49ab8fa46.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON v2_job_completed (workspace_id, started_at DESC)", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "931703a98d2ee5fb58d3380896baaee032e731db1e6bd49d991a54f49ab8fa46" -} diff --git a/backend/.sqlx/query-ea9385509319f66b9330221eb50b85edafb9408d0306f17bb78b65a5d81c570b.json b/backend/.sqlx/query-ea9385509319f66b9330221eb50b85edafb9408d0306f17bb78b65a5d81c570b.json new file mode 100644 index 0000000000..ab648f579d --- /dev/null +++ b/backend/.sqlx/query-ea9385509319f66b9330221eb50b85edafb9408d0306f17bb78b65a5d81c570b.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS ix_v2_job_root_by_path", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "ea9385509319f66b9330221eb50b85edafb9408d0306f17bb78b65a5d81c570b" +} diff --git a/backend/.sqlx/query-f17c9fed09897191ee70214223d4b83a05f1d649bfedff9f24cc3e6c702d42df.json b/backend/.sqlx/query-f17c9fed09897191ee70214223d4b83a05f1d649bfedff9f24cc3e6c702d42df.json new file mode 100644 index 0000000000..a68b5dd969 --- /dev/null +++ b/backend/.sqlx/query-f17c9fed09897191ee70214223d4b83a05f1d649bfedff9f24cc3e6c702d42df.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_job_v2_job_root_by_path_2 ON v2_job (workspace_id, runnable_path) WHERE parent_job IS NULL;", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "f17c9fed09897191ee70214223d4b83a05f1d649bfedff9f24cc3e6c702d42df" +} diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 6375018798..475c04627e 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -8058,11 +8058,12 @@ paths: - $ref: "#/components/parameters/StartedAfter" - $ref: "#/components/parameters/CreatedBefore" - $ref: "#/components/parameters/CreatedAfter" - - $ref: "#/components/parameters/CreatedOrStartedBefore" + - $ref: "#/components/parameters/CompletedBefore" + - $ref: "#/components/parameters/CompletedAfter" + - $ref: "#/components/parameters/CreatedBeforeQueue" + - $ref: "#/components/parameters/CreatedAfterQueue" - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/ScheduledForBeforeNow" - - $ref: "#/components/parameters/CreatedOrStartedAfter" - - $ref: "#/components/parameters/CreatedOrStartedAfterCompletedJob" - $ref: "#/components/parameters/JobKinds" - $ref: "#/components/parameters/Suspended" - $ref: "#/components/parameters/ArgsFilter" @@ -8272,19 +8273,18 @@ paths: - $ref: "#/components/parameters/StartedAfter" - $ref: "#/components/parameters/CreatedBefore" - $ref: "#/components/parameters/CreatedAfter" - - $ref: "#/components/parameters/CreatedOrStartedBefore" + - $ref: "#/components/parameters/CompletedBefore" + - $ref: "#/components/parameters/CompletedAfter" + - $ref: "#/components/parameters/CreatedBeforeQueue" + - $ref: "#/components/parameters/CreatedAfterQueue" - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/ScheduledForBeforeNow" - - $ref: "#/components/parameters/CreatedOrStartedAfter" - - $ref: "#/components/parameters/CreatedOrStartedAfterCompletedJob" - $ref: "#/components/parameters/JobKinds" - $ref: "#/components/parameters/Suspended" - $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 description: is the job skipped in: query @@ -14245,11 +14245,12 @@ paths: - $ref: "#/components/parameters/ScriptExactHash" - $ref: "#/components/parameters/StartedBefore" - $ref: "#/components/parameters/StartedAfter" - - $ref: "#/components/parameters/CreatedOrStartedBefore" - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/ScheduledForBeforeNow" - - $ref: "#/components/parameters/CreatedOrStartedAfter" - - $ref: "#/components/parameters/CreatedOrStartedAfterCompletedJob" + - $ref: "#/components/parameters/CompletedBefore" + - $ref: "#/components/parameters/CompletedAfter" + - $ref: "#/components/parameters/CreatedBeforeQueue" + - $ref: "#/components/parameters/CreatedAfterQueue" - $ref: "#/components/parameters/JobKinds" - $ref: "#/components/parameters/ArgsFilter" - $ref: "#/components/parameters/Tag" @@ -14838,33 +14839,40 @@ components: schema: type: string format: date-time - CreatedOrStartedAfter: - name: created_or_started_after - description: - filter on created_at for non non started job and started_at otherwise - after (exclusive) timestamp + + CompletedBefore: + name: completed_before + description: filter on started before (inclusive) timestamp in: query schema: type: string format: date-time - CreatedOrStartedAfterCompletedJob: - name: created_or_started_after_completed_jobs - description: - filter on created_at for non non started job and started_at otherwise - after (exclusive) timestamp but only for the completed jobs + CompletedAfter: + name: completed_after + description: filter on started after (exclusive) timestamp in: query schema: type: string format: date-time - CreatedOrStartedBefore: - name: created_or_started_before + + CreatedAfterQueue: + name: created_after_queue description: - filter on created_at for non non started job and started_at otherwise - before (inclusive) timestamp + filter on jobs created after X for jobs in the queue only in: query schema: type: string format: date-time + + CreatedBeforeQueue: + name: created_before_queue + description: + filter on jobs created before X for jobs in the queue only + in: query + schema: + type: string + format: date-time + Success: name: success description: filter on successful jobs @@ -15669,6 +15677,9 @@ components: started_at: type: string format: date-time + completed_at: + type: string + format: date-time duration_ms: type: integer success: @@ -16302,30 +16313,30 @@ components: ScriptLang: type: string enum: [ - python3, - deno, - go, - bash, - powershell, - postgresql, - mysql, - bigquery, - snowflake, - mssql, - oracledb, - graphql, - nativets, - bun, - php, - rust, - ansible, - csharp, - nu, - java, - ruby, - duckdb, - # for related places search: ADD_NEW_LANG - ] + python3, + deno, + go, + bash, + powershell, + postgresql, + mysql, + bigquery, + snowflake, + mssql, + oracledb, + graphql, + nativets, + bun, + php, + rust, + ansible, + csharp, + nu, + java, + ruby, + duckdb, + # for related places search: ADD_NEW_LANG + ] Preview: type: object diff --git a/backend/windmill-api/src/concurrency_groups.rs b/backend/windmill-api/src/concurrency_groups.rs index db1341132c..bfd0b8182f 100644 --- a/backend/windmill-api/src/concurrency_groups.rs +++ b/backend/windmill-api/src/concurrency_groups.rs @@ -166,7 +166,7 @@ async fn get_concurrent_intervals( .clone(); let mut sqlb_c = SqlBuilder::select_from("v2_job_completed") .fields(UnifiedJob::completed_job_fields()) - .order_by("started_at", lq.order_desc.unwrap_or(true)) + .order_by("completed_at", lq.order_desc.unwrap_or(true)) .limit(row_limit) .clone(); let mut sqlb_q_user = SqlBuilder::select_from("v2_job_queue") @@ -176,7 +176,7 @@ async fn get_concurrent_intervals( .clone(); let mut sqlb_c_user = SqlBuilder::select_from("v2_job_completed") .fields(&["id"]) - .order_by("started_at", lq.order_desc.unwrap_or(true)) + .order_by("completed_at", lq.order_desc.unwrap_or(true)) .limit(row_limit) .clone(); @@ -209,6 +209,10 @@ async fn get_concurrent_intervals( started_after: _, created_before: _, created_after: _, + created_before_queue: _, + created_after_queue: _, + completed_after: _, + completed_before: _, created_or_started_before: _, created_or_started_after: _, created_or_started_after_completed_jobs: _, @@ -296,6 +300,7 @@ async fn get_concurrent_intervals( duration_ms: j.duration_ms, }) .collect(); + let jobs = running_jobs_db .into_iter() .filter(|j| running_jobs_user.iter().any(|id| j.id == *id)) @@ -306,6 +311,7 @@ async fn get_concurrent_intervals( ) .map(From::from) .collect(); + Ok(Json(ExtendedJobs { jobs, obscured_jobs, diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index cb6fa50b94..1c1deefa4f 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -778,7 +778,7 @@ macro_rules! get_job_query { ("v2_job_completed", $($opts:tt)*) => { get_job_query!( @impl "v2_job_completed", ($($opts)*), - "v2_job_completed.duration_ms, CASE WHEN status = 'success' OR status = 'skipped' THEN true ELSE false END as success, result_columns, deleted, status = 'skipped' as is_skipped, result->'wm_labels' as labels, \ + "v2_job_completed.duration_ms, v2_job_completed.completed_at, CASE WHEN status = 'success' OR status = 'skipped' THEN true ELSE false END as success, result_columns, deleted, status = 'skipped' as is_skipped, result->'wm_labels' as labels, \ CASE WHEN result is null or pg_column_size(result) < 90000 THEN result ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as result", "", ) @@ -1820,8 +1820,8 @@ impl From for ListQueueQuery { created_by: lcq.created_by, started_before: lcq.started_before, started_after: lcq.started_after, - created_before: lcq.created_before, - created_after: lcq.created_after, + created_before: lcq.created_before_queue.or(lcq.created_before), + created_after: lcq.created_after_queue.or(lcq.created_after), created_or_started_before: lcq.created_or_started_before, created_or_started_after: lcq.created_or_started_after, worker: lcq.worker, @@ -1855,11 +1855,11 @@ pub fn filter_list_queue_query( if join_outstanding_wait_times { sqlb.left() .join("outstanding_wait_time") - .on_eq("v2_job.id", "outstanding_wait_time.job_id"); + .on_eq("v2_job_queue.id", "outstanding_wait_time.job_id"); } if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) { - sqlb.and_where_eq("v2_job.workspace_id", "?".bind(&w_id)); + sqlb.and_where_eq("v2_job_queue.workspace_id", "?".bind(&w_id)); } if let Some(w) = &lq.worker { @@ -1960,8 +1960,7 @@ pub fn filter_list_queue_query( } if lq.is_not_schedule.unwrap_or(false) { - sqlb.and_where("trigger_kind != 'schedule'") - .or_where("trigger_kind IS NULL"); + sqlb.and_where("trigger_kind IS DISTINCT FROM 'schedule'"); } sqlb @@ -2360,10 +2359,13 @@ async fn list_jobs( Query(pagination): Query, Query(lq): Query, ) -> error::JsonResult> { - let limit = pagination.per_page.unwrap_or(1000); let (per_page, offset) = paginate(pagination); let lqc = lq.clone(); + if offset > 0 { + tracing::warn!("offset is not 0, but is ignored for list_jobs. Use created_before or completed_before instead."); + } + if lq.success.is_some() && lq.running.is_some_and(|x| x) { return Err(error::Error::BadRequest( "cannot specify both success and running".to_string(), @@ -2372,7 +2374,7 @@ async fn list_jobs( let sqlc = if lq.running.is_none() { Some(list_completed_jobs_query( &w_id, - Some(per_page + offset), + Some(per_page), 0, &ListCompletedQuery { order_desc: Some(true), ..lqc }, UnifiedJob::completed_job_fields(), @@ -2392,19 +2394,13 @@ async fn list_jobs( &w_id, &ListQueueQuery { order_desc: Some(true), ..lq.into() }, UnifiedJob::queued_job_fields(), - Pagination { per_page: Some(limit), page: None }, + Pagination { per_page: None, page: None }, true, get_scope_tags(&authed), ); if let Some(sqlc) = sqlc { - format!( - "{} UNION ALL {} LIMIT {} OFFSET {};", - &sqlq.subquery()?, - &sqlc.subquery()?, - per_page, - offset - ) + format!("{} UNION ALL {}", &sqlq.subquery()?, &sqlc.subquery()?,) } else { sqlq.limit(per_page).offset(offset).query()? } @@ -2418,6 +2414,7 @@ async fn list_jobs( } sqlc.unwrap().limit(per_page).offset(offset).query()? }; + // tracing::info!("sql: {}", sql); let mut tx: Transaction<'_, Postgres> = user_db.begin(&authed).await?; let jobs: Vec = sqlx::query_as(&sql) @@ -3295,6 +3292,7 @@ pub struct UnifiedJob { pub created_by: String, pub created_at: chrono::DateTime, pub started_at: Option>, + pub completed_at: Option>, pub scheduled_for: Option>, pub running: Option, pub script_hash: Option, @@ -3327,13 +3325,14 @@ pub struct UnifiedJob { const CJ_FIELDS: &[&str] = &[ "'CompletedJob' as typ", - "v2_job.id", - "v2_job.workspace_id", + "v2_job_completed.id", + "v2_job_completed.workspace_id", "v2_job.parent_job", "v2_job.created_by", "v2_job.created_at", "v2_job_completed.started_at", "null as scheduled_for", + "v2_job_completed.completed_at", "null as running", "v2_job.runnable_id as script_hash", "v2_job.runnable_path as script_path", @@ -3366,13 +3365,14 @@ const CJ_FIELDS: &[&str] = &[ const QJ_FIELDS: &[&str] = &[ "'QueuedJob' as typ", - "v2_job.id", - "v2_job.workspace_id", + "v2_job_queue.id", + "v2_job_queue.workspace_id", "v2_job.parent_job", "v2_job.created_by", - "v2_job.created_at", + "v2_job_queue.created_at", "v2_job_queue.started_at", "v2_job_queue.scheduled_for", + "null as completed_at", "v2_job_queue.running", "v2_job.runnable_id as script_hash", "v2_job.runnable_path as script_path", @@ -3425,6 +3425,7 @@ impl<'a> From for Job { created_by: uj.created_by, created_at: uj.created_at, started_at: uj.started_at, + completed_at: uj.completed_at, duration_ms: uj.duration_ms.unwrap(), success: uj.success.unwrap(), script_hash: uj.script_hash, @@ -7507,7 +7508,7 @@ pub fn filter_list_completed_query( if join_outstanding_wait_times { sqlb.left() .join("outstanding_wait_time") - .on_eq("v2_job.id", "outstanding_wait_time.job_id"); + .on_eq("v2_job_completed.id", "outstanding_wait_time.job_id"); } if let Some(label) = &lq.label { @@ -7535,7 +7536,8 @@ pub fn filter_list_completed_query( } if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) { - sqlb.and_where_eq("v2_job.workspace_id", "?".bind(&w_id)); + sqlb.and_where_eq("v2_job_completed.workspace_id", "?".bind(&w_id)) + .and_where_eq("v2_job.workspace_id", "?".bind(&w_id)); } if let Some(p) = &lq.schedule_path { @@ -7605,6 +7607,13 @@ pub fn filter_list_completed_query( sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339())); } + if let Some(dt) = &lq.completed_after { + sqlb.and_where_ge("completed_at", "?".bind(&dt.to_rfc3339())); + } + if let Some(dt) = &lq.completed_before { + sqlb.and_where_le("completed_at", "?".bind(&dt.to_rfc3339())); + } + if let Some(sk) = &lq.is_skipped { if *sk { sqlb.and_where_eq("status", "'skipped'"); @@ -7640,8 +7649,7 @@ pub fn filter_list_completed_query( } if lq.is_not_schedule.unwrap_or(false) { - sqlb.and_where("trigger_kind != 'schedule'") - .or_where("trigger_kind IS NULL"); + sqlb.and_where("trigger_kind IS DISTINCT FROM 'schedule'"); } sqlb @@ -7658,7 +7666,14 @@ pub fn list_completed_jobs_query( ) -> SqlBuilder { let mut sqlb = SqlBuilder::select_from("v2_job_completed") .fields(fields) - .order_by("v2_job.created_at", lq.order_desc.unwrap_or(true)) + .order_by( + if lq.completed_before.is_some() || lq.completed_after.is_some() { + "v2_job_completed.completed_at" + } else { + "v2_job.created_at" + }, + lq.order_desc.unwrap_or(true), + ) .offset(offset) .clone(); if let Some(per_page) = per_page { @@ -7687,6 +7702,10 @@ pub struct ListCompletedQuery { pub created_or_started_before: Option>, pub created_or_started_after: Option>, pub created_or_started_after_completed_jobs: Option>, + pub created_before_queue: Option>, + pub created_after_queue: Option>, + pub completed_after: Option>, + pub completed_before: Option>, pub success: Option, pub running: Option, pub parent_job: Option, @@ -7726,8 +7745,8 @@ async fn list_completed_jobs( offset, &lq, &[ - "v2_job.id", - "v2_job.workspace_id", + "v2_job_completed.id", + "v2_job_completed.workspace_id", "v2_job.parent_job", "v2_job.created_by", "v2_job.created_at", diff --git a/backend/windmill-api/src/live_migrations.rs b/backend/windmill-api/src/live_migrations.rs index 0e3fb97e02..18e05967b0 100644 --- a/backend/windmill-api/src/live_migrations.rs +++ b/backend/windmill-api/src/live_migrations.rs @@ -447,19 +447,6 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { i += 1; tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON v2_job_completed (workspace_id, started_at DESC)") - .execute(db) - .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - - sqlx::query!("create index concurrently if not exists ix_job_root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL") - .execute(db) - .await?; - - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path_2") .execute(db) .await?; @@ -467,13 +454,6 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { i += 1; tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("create index concurrently if not exists ix_job_created_at ON v2_job (created_at DESC)") - .execute(db) - .await?; - - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query( "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_created_at_new_2", ) @@ -523,9 +503,9 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { }); run_windmill_migration!("v2_improve_v2_job_indices_ii", &db, |tx| { - sqlx::query!("create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlescriptflow') AND parent_job IS NULL") - .execute(db) - .await?; + sqlx::query!("create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlestepflow') AND parent_job IS NULL") + .execute(db) + .await?; sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_6") .execute(db) @@ -609,5 +589,52 @@ WHERE operation IN ('users.login', 'oauth.login', 'users.token.refresh');" .execute(db) .await?; }); + + run_windmill_migration!("v2_job_completed_completed_at_9", db, |tx| { + let migration_job_name = "v2_job_completed_completed_at"; + let mut i = 1; + tracing::info!("step {i} of {migration_job_name} migration"); + sqlx::query!("create index concurrently if not exists ix_job_workspace_id_completed_at_all ON v2_job_completed (workspace_id, completed_at DESC)") + .execute(db) + .await?; + i += 1; + + sqlx::query!("CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_job_v2_job_root_by_path_2 ON v2_job (workspace_id, runnable_path) WHERE parent_job IS NULL;") + .execute(db) + .await?; + + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query!("create index concurrently if not exists ix_job_root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL") + .execute(db) + .await?; + + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query!( + "DROP INDEX CONCURRENTLY IF EXISTS ix_completed_job_workspace_id_started_at_new_2" + ) + .execute(db) + .await?; + + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_job_created_at") + .execute(db) + .await?; + + i += 1; + + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_v2_job_root_by_path") + .execute(db) + .await?; + + i += 1; + tracing::info!("step {i} of {migration_job_name} migration"); + }); + Ok(()) } diff --git a/backend/windmill-api/src/schedule.rs b/backend/windmill-api/src/schedule.rs index 3b7413781b..134ea46246 100644 --- a/backend/windmill-api/src/schedule.rs +++ b/backend/windmill-api/src/schedule.rs @@ -583,7 +583,7 @@ async fn list_schedule_with_jobs( AND j.workspace_id = $1 AND parent_job IS NULL AND runnable_path = schedule.script_path AND status <> 'skipped' - ORDER BY created_at DESC + ORDER BY completed_at DESC LIMIT 20 ) AS jobs) t WHERE workspace_id = $1 diff --git a/backend/windmill-common/src/jobs.rs b/backend/windmill-common/src/jobs.rs index 49af82bb64..f32b3447c8 100644 --- a/backend/windmill-common/src/jobs.rs +++ b/backend/windmill-common/src/jobs.rs @@ -263,6 +263,7 @@ pub struct CompletedJob { pub created_by: String, pub created_at: chrono::DateTime, pub started_at: Option>, + pub completed_at: Option>, pub duration_ms: i64, pub success: bool, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 299c0231d9..f2950df1d1 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -2427,8 +2427,7 @@ pub async fn pull( } #[cfg(not(feature = "enterprise"))] - let has_concurent_limit = false - || (job.is_dependency() && job.concurrent_limit.is_some() && cfg!(feature = "private") && !*WMDEBUG_NO_DJOB_DEBOUNCING); + let has_concurent_limit = job.is_dependency() && job.concurrent_limit.is_some() && cfg!(feature = "private") && !*WMDEBUG_NO_DJOB_DEBOUNCING; // if we don't have private flag, we don't have concurrency limit // concurrency check. If more than X jobs for this path are already running, we re-queue and pull another job from the queue diff --git a/frontend/src/lib/components/FlowHistoryJobPicker.svelte b/frontend/src/lib/components/FlowHistoryJobPicker.svelte index 61e3765be8..891df97e1b 100644 --- a/frontend/src/lib/components/FlowHistoryJobPicker.svelte +++ b/frontend/src/lib/components/FlowHistoryJobPicker.svelte @@ -1,15 +1,24 @@ - - - - -
- { - if (e.detail) { - dispatch('select', { jobId: e.detail?.jobId, initial: false }) - } else { - dispatch('unselect') - } - }} - {selected} - runnableId={path} - runnableType={'FlowPath'} - /> -
-
+ {#snippet trigger()} + + + + {/snippet} + {#snippet content()} + +
+ { + if (e.detail) { + dispatch('select', { jobId: e.detail?.jobId, initial: false }) + } else { + dispatch('unselect') + } + }} + {selected} + runnableId={path} + runnableType={'FlowPath'} + /> +
+ + {/snippet}
diff --git a/frontend/src/lib/components/RunChart.svelte b/frontend/src/lib/components/RunChart.svelte index e5643f5eb4..d40cddc808 100644 --- a/frontend/src/lib/components/RunChart.svelte +++ b/frontend/src/lib/components/RunChart.svelte @@ -137,10 +137,10 @@ } function minJobTime(jobs: CompletedJob[]): Date { - let min: Date = new Date(jobs[0].started_at) + let min: Date = new Date(jobs[0].completed_at!) for (const job of jobs) { - if (job.started_at != undefined) { - const date = new Date(job.started_at) + if (job.completed_at != undefined) { + const date = new Date(job.completed_at) if (date < min) { min = date } @@ -150,10 +150,10 @@ } function maxJobTime(jobs: CompletedJob[]): Date { - let max: Date = new Date(jobs[0].started_at) + let max: Date = new Date(jobs[0].completed_at!) for (const job of jobs) { - if (new Date(job.started_at) > max) { - max = new Date(job.started_at) + if (new Date(job.completed_at!) > max) { + max = new Date(job.completed_at!) } } return max diff --git a/frontend/src/lib/components/SavedInputs.svelte b/frontend/src/lib/components/SavedInputs.svelte index fd6c565d18..028972f868 100644 --- a/frontend/src/lib/components/SavedInputs.svelte +++ b/frontend/src/lib/components/SavedInputs.svelte @@ -1,4 +1,5 @@ diff --git a/frontend/src/lib/components/runs/RunRow.svelte b/frontend/src/lib/components/runs/RunRow.svelte index e38959f881..3af5c33601 100644 --- a/frontend/src/lib/components/runs/RunRow.svelte +++ b/frontend/src/lib/components/runs/RunRow.svelte @@ -181,9 +181,14 @@
{#if job} - {#if 'started_at' in job && job.started_at} - {isJobRecent ? 'Started' : ''} - + {#if ('started_at' in job && job.started_at) || ('completed_at' in job && job.completed_at)} + {#if 'completed_at' in job && job.completed_at} + {isJobRecent ? 'Ended' : ''} + + {:else if 'started_at' in job && job.started_at} + {isJobRecent ? 'Started' : ''} + + {/if} {#if job && (job.self_wait_time_ms || job.aggregate_wait_time_ms)} ) {/if} {:else if `scheduled_for` in job && job.scheduled_for && forLater(job.scheduled_for)} - Waiting for executor (scheduled for ) {:else} - Waiting for executor (created ) + Waiting executor () {/if} {/if}
diff --git a/frontend/src/lib/components/runs/RunsTable.svelte b/frontend/src/lib/components/runs/RunsTable.svelte index ac6a3f771d..341d40d834 100644 --- a/frontend/src/lib/components/runs/RunsTable.svelte +++ b/frontend/src/lib/components/runs/RunsTable.svelte @@ -37,7 +37,7 @@ }: Props = $props() function getTime(job: Job): string | undefined { - return job['started_at'] ?? job['scheduled_for'] ?? job['created_at'] + return job['completed_at'] ?? job['started_at'] ?? job['scheduled_for'] ?? job['created_at'] } function groupJobsByDay(jobs: Job[]): { diff --git a/frontend/src/lib/components/stepHistoryLoader.svelte.ts b/frontend/src/lib/components/stepHistoryLoader.svelte.ts index c82bf78b94..3e927fd34f 100644 --- a/frontend/src/lib/components/stepHistoryLoader.svelte.ts +++ b/frontend/src/lib/components/stepHistoryLoader.svelte.ts @@ -109,7 +109,7 @@ export class StepHistoryLoader { ? module.value.path : (initialPath === '' ? path : initialPath) + '/' + module.id - const previousJobId = await JobService.listJobs({ + const previousJobId = await JobService.listCompletedJobs({ workspace: workspaceId, scriptPathExact: scriptPath, jobKinds: ['preview', 'script', 'flowpreview', 'flow', 'flowscript'].join(','), From a3a68c4fef5d5d4a7d9b90bacb3f0b6f3fe9e3b7 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 27 Oct 2025 15:01:32 +0000 Subject: [PATCH 02/32] nit --- cli/src/commands/script/script.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/commands/script/script.ts b/cli/src/commands/script/script.ts index 03c03b4fe9..a0cf9d9fbb 100644 --- a/cli/src/commands/script/script.ts +++ b/cli/src/commands/script/script.ts @@ -938,7 +938,7 @@ async function generateMetadata( scriptPath: string | undefined ) { log.info( - "This command only works for workspace scripts, for flows inline scripts use `wmill flow generate - locks`" + "This command only works for workspace scripts, for flows inline scripts use `wmill flow generate-locks`" ); if (scriptPath == "") { scriptPath = undefined; From bdf5db5fa87fb725527088900dd45ad3e45a5f4e Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:07:08 +0100 Subject: [PATCH 03/32] Fix Custom system prompts settings (#6954) * Fix Custom system prompts settings * fix CI --- .../src/lib/components/UserSettings.svelte | 2 -- .../components/settings/AIUserSettings.svelte | 3 +++ .../settings/UserAIPromptsSettings.svelte | 26 +++++-------------- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/frontend/src/lib/components/UserSettings.svelte b/frontend/src/lib/components/UserSettings.svelte index 5471e21f10..489ee865a3 100644 --- a/frontend/src/lib/components/UserSettings.svelte +++ b/frontend/src/lib/components/UserSettings.svelte @@ -7,7 +7,6 @@ import { createEventDispatcher } from 'svelte' import UserInfoSettings from './settings/UserInfoSettings.svelte' import AIUserSettings from './settings/AIUserSettings.svelte' - import UserAIPromptsSettings from './settings/UserAIPromptsSettings.svelte' interface Props { scopes?: string[] | undefined @@ -70,7 +69,6 @@
-
{/if} diff --git a/frontend/src/lib/components/settings/AIUserSettings.svelte b/frontend/src/lib/components/settings/AIUserSettings.svelte index 09b07e6c05..c512ba6f78 100644 --- a/frontend/src/lib/components/settings/AIUserSettings.svelte +++ b/frontend/src/lib/components/settings/AIUserSettings.svelte @@ -7,6 +7,7 @@ import { getLocalSetting, storeLocalSetting } from '$lib/utils' import Toggle from '../Toggle.svelte' import type { Writable } from 'svelte/store' + import UserAIPromptsSettings from './UserAIPromptsSettings.svelte' $effect(() => { loadSettings() @@ -62,4 +63,6 @@ }} /> + + diff --git a/frontend/src/lib/components/settings/UserAIPromptsSettings.svelte b/frontend/src/lib/components/settings/UserAIPromptsSettings.svelte index f752a58b81..8d87f25171 100644 --- a/frontend/src/lib/components/settings/UserAIPromptsSettings.svelte +++ b/frontend/src/lib/components/settings/UserAIPromptsSettings.svelte @@ -2,14 +2,13 @@ import { storeLocalSetting } from '$lib/utils' import CustomAIPrompts from '../copilot/CustomAIPrompts.svelte' import Button from '../common/button/Button.svelte' - import { ChevronDown, ChevronRight } from 'lucide-svelte' import { sendUserToast } from '$lib/toast' import { getUserCustomPrompts } from '$lib/aiStore' + import Section from '../Section.svelte' const USER_CUSTOM_PROMPTS_KEY = 'userCustomAIPrompts' let customPrompts = $state>(getUserCustomPrompts()) - let isExpanded = $state(false) function save() { storeLocalSetting(USER_CUSTOM_PROMPTS_KEY, JSON.stringify(customPrompts)) @@ -20,23 +19,10 @@
- - - {#if isExpanded} +
+ {#snippet header()} +
+ {/snippet}
Save
- {/if} + From f57d5d5a2258bc470f3b9121e71f68f3db65e5e3 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 27 Oct 2025 15:23:28 +0000 Subject: [PATCH 04/32] nit --- backend/windmill-api/openapi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 475c04627e..625e3ba66e 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -8285,6 +8285,7 @@ paths: - $ref: "#/components/parameters/Tag" - $ref: "#/components/parameters/ResultFilter" - $ref: "#/components/parameters/AllowWildcards" + - $ref: "#/components/parameters/PerPage" - name: is_skipped description: is the job skipped in: query From 0b82ff4ebb62171f0b4fbcb1ecf0ecf64539f441 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:46:28 +0100 Subject: [PATCH 05/32] New color palettes (#6945) * debug runs text fix * New color palette * Remove luminance-blue * replace hardcoded flow node colors * nit --- frontend/src/lib/assets/tokens/tokens.json | 67 ++++++-- frontend/src/lib/components/Toggle.svelte | 2 +- .../apps/editor/AppEditorHeader.svelte | 2 +- .../src/lib/components/common/alert/model.ts | 9 +- .../lib/components/common/badge/Badge.svelte | 11 +- .../components/common/button/Button.svelte | 2 +- .../src/lib/components/common/button/model.ts | 14 +- .../ConfirmationModal.svelte | 2 +- frontend/src/lib/components/graph/util.ts | 18 +-- frontend/tailwind.config.cjs | 146 ++++++++---------- 10 files changed, 149 insertions(+), 124 deletions(-) diff --git a/frontend/src/lib/assets/tokens/tokens.json b/frontend/src/lib/assets/tokens/tokens.json index 3dd358a9a7..61ada10cac 100644 --- a/frontend/src/lib/assets/tokens/tokens.json +++ b/frontend/src/lib/assets/tokens/tokens.json @@ -123,16 +123,16 @@ "deep-blue-200": "#9da6ca", "deep-blue-100": "#c3c9df", "deep-blue-50": "#e7eaf2", - "luminance-blue-900": "#1e3a8a", - "luminance-blue-800": "#0d3cc5", - "luminance-blue-700": "#1847d2", - "luminance-blue-600": "#2652df", - "luminance-blue-500": "#2c5beb", - "luminance-blue-400": "#5074f6", - "luminance-blue-300": "#758ff8", - "luminance-blue-200": "#a0affa", - "luminance-blue-100": "#c7cefc", - "luminance-blue-50": "#e9ecfe", + "blue-900": "#1e3a8a", + "blue-800": "#183faf", + "blue-700": "#1847d2", + "blue-600": "#2652df", + "blue-500": "#2c5beb", + "blue-400": "#5074f6", + "blue-300": "#758ff8", + "blue-200": "#a0affa", + "blue-100": "#c7cefc", + "blue-50": "#e9ecfe", "nord-0": "#2e3440", "nord-1": "#3b4252", "nord-2": "#434c5e", @@ -148,7 +148,52 @@ "nord-12": "#d08770", "nord-13": "#ebcb8b", "nord-14": "#a3be8c", - "nord-15": "#b48ead" + "nord-15": "#b48ead", + "red-800": "#693237", + "red-600": "#aa3e47", + "red-500": "#e63b49", + "red-400": "#f87171", + "red-200": "#fecaca", + "red-950": "#392b31", + "red-100": "#fee2e2", + "red-900": "#4c2d32", + "red-700": "#81383f", + "red-300": "#fca5a5", + "red-50": "#fef2f2", + "green-50": "#f0fdf4", + "green-100": "#dcfce7", + "green-200": "#bbf7d0", + "green-300": "#96f2b7", + "green-400": "#62e993", + "green-500": "#32c76d", + "green-600": "#319e69", + "green-700": "#3b7a5b", + "green-800": "#3b6054", + "green-900": "#284945", + "green-950": "#263b3d", + "orange-50": "#fff7ed", + "orange-100": "#ffedd5", + "orange-200": "#fed7aa", + "orange-300": "#fdba74", + "orange-400": "#fb923c", + "orange-500": "#f0721b", + "orange-600": "#cd6230", + "orange-700": "#905035", + "orange-800": "#654338", + "orange-900": "#4b3531", + "orange-950": "#3c2c2ddb", + "purple-50": "#faf5ff", + "purple-100": "#f3e8ff", + "purple-200": "#e5cdff", + "purple-300": "#cfa5fc", + "purple-400": "#b267fd", + "purple-500": "#9939f5", + "purple-600": "#8143ba", + "purple-700": "#5f407d", + "purple-800": "#483c60", + "purple-900": "#3a3549", + "purple-950": "#31313f", + "blue-950": "#213263" } }, "guidelines": { "mode-1": { "blue": "#5e81ac", "demo-background": "#ffffff00" } }, diff --git a/frontend/src/lib/components/Toggle.svelte b/frontend/src/lib/components/Toggle.svelte index 1189980cf3..6b502bcbfa 100644 --- a/frontend/src/lib/components/Toggle.svelte +++ b/frontend/src/lib/components/Toggle.svelte @@ -112,7 +112,7 @@ color == 'red' ? 'peer-checked:bg-red-600' : color == 'blue' - ? 'peer-checked:bg-luminance-blue-400 ' + ? 'peer-checked:bg-blue-400 ' : 'peer-checked:bg-nord-950 dark:peer-checked:bg-nord-900', size === 'md' ? 'w-11 h-6 after:top-0.5 after:left-[2px] after:h-5 after:w-5' diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index 59fb4b73e1..e7ad74af92 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -1296,7 +1296,7 @@ >
Debug runs
-
({$jobs?.length > 99 ? '99+' : ($jobs?.length ?? 0)})
{#if hasErrors} diff --git a/frontend/src/lib/components/common/alert/model.ts b/frontend/src/lib/components/common/alert/model.ts index d7d8883554..356701e06d 100644 --- a/frontend/src/lib/components/common/alert/model.ts +++ b/frontend/src/lib/components/common/alert/model.ts @@ -2,11 +2,10 @@ export type AlertType = 'success' | 'error' | 'warning' | 'info' export const classes: Record> = { info: { - bgClass: - 'bg-luminance-blue-50 border-luminance-blue-100 border dark:bg-luminance-blue-900/60 dark:border-luminance-blue-700/40', - iconClass: 'text-luminance-blue-600 dark:text-luminance-blue-50', - titleClass: 'text-luminance-blue-700 dark:text-luminance-blue-50', - descriptionClass: 'text-luminance-blue-600 dark:text-luminance-blue-50/80' + bgClass: 'bg-blue-50 border-blue-100 border dark:bg-blue-900/60 dark:border-blue-700/40', + iconClass: 'text-blue-600 dark:text-blue-50', + titleClass: 'text-blue-700 dark:text-blue-50', + descriptionClass: 'text-blue-600 dark:text-blue-50/80' }, warning: { bgClass: diff --git a/frontend/src/lib/components/common/badge/Badge.svelte b/frontend/src/lib/components/common/badge/Badge.svelte index fa3f06d7e3..91429bd291 100644 --- a/frontend/src/lib/components/common/badge/Badge.svelte +++ b/frontend/src/lib/components/common/badge/Badge.svelte @@ -48,7 +48,7 @@ let hidden = $state(false) const colors: Record = { gray: 'bg-surface-sunken text-primary', - blue: 'bg-luminance-blue-50 text-luminance-blue-800 dark:text-luminance-blue-100 dark:bg-luminance-blue-700/40', + blue: 'bg-blue-50 text-blue-800 dark:text-blue-100 dark:bg-blue-700/40', red: 'bg-red-100 text-red-800 dark:bg-red-700/40 dark:text-red-100', green: 'bg-green-100 text-green-700 dark:bg-green-700/40 dark:text-green-100', yellow: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-700/40 dark:text-yellow-100', @@ -68,7 +68,7 @@ const selectedColors: Record = { gray: 'bg-surface-input text-primary', - blue: 'bg-luminance-blue-500 text-white dark:bg-luminance-blue-600', + blue: 'bg-blue-500 text-white dark:bg-blue-600', red: 'bg-red-500 text-white dark:bg-red-600', green: 'bg-green-500 text-white dark:bg-green-600', yellow: 'bg-yellow-500 text-white dark:bg-yellow-600', @@ -76,8 +76,7 @@ indigo: 'bg-indigo-500 text-white dark:bg-indigo-600', violet: 'bg-violet-500 text-white dark:bg-violet-600', ['dark-gray']: 'bg-gray-700 text-gray-100 dark:bg-gray-800 dark:text-gray-200', - ['dark-blue']: - 'bg-luminance-blue-700 text-luminance-blue-100 dark:bg-luminance-blue-800 dark:text-luminance-blue-200', + ['dark-blue']: 'bg-blue-700 text-blue-100 dark:bg-blue-800 dark:text-blue-200', ['dark-red']: 'bg-red-700 text-white dark:bg-red-800 dark:text-red-100', ['dark-green']: 'bg-green-700 text-green-100 dark:bg-green-800 dark:text-green-200', ['dark-yellow']: 'bg-yellow-600 text-white dark:bg-yellow-700 dark:text-yellow-100', @@ -89,7 +88,7 @@ const hovers: Partial> = { gray: 'hover:bg-surface-hover', - blue: 'hover:bg-luminance-blue-200 dark:hover:bg-luminance-blue-700/40', + blue: 'hover:bg-blue-200 dark:hover:bg-blue-700/40', red: 'hover:bg-red-200 dark:hover:bg-red-500/25', green: 'hover:bg-green-200 dark:hover:bg-green-500/25', yellow: 'hover:bg-yellow-200 dark:hover:bg-yellow-500/25', @@ -97,7 +96,7 @@ orange: 'hover:bg-orange-200 dark:hover:bg-orange-500/25', violet: 'hover:bg-violet-200 dark:hover:bg-violet-500/25', ['dark-gray']: 'hover:bg-gray-600 dark:hover:bg-gray-700', - ['dark-blue']: 'hover:bg-luminance-blue-600 dark:hover:bg-luminance-blue-700', + ['dark-blue']: 'hover:bg-blue-600 dark:hover:bg-blue-700', ['dark-red']: 'hover:bg-red-600 dark:hover:bg-red-700', ['dark-green']: 'hover:bg-green-600 dark:hover:bg-green-700', ['dark-yellow']: 'hover:bg-yellow-600 dark:hover:bg-yellow-700', diff --git a/frontend/src/lib/components/common/button/Button.svelte b/frontend/src/lib/components/common/button/Button.svelte index 9ed11fb094..0345e4a8fc 100644 --- a/frontend/src/lib/components/common/button/Button.svelte +++ b/frontend/src/lib/components/common/button/Button.svelte @@ -215,7 +215,7 @@ if (variant === 'default') { return 'border border-border-light divide-x divide-border-light' } else if (variant === 'accent') { - return 'divide-x divide-luminance-blue-100 dark:divide-luminance-blue-200' + return 'divide-x divide-blue-100 dark:divide-blue-200' } else if (variant === 'accent-secondary') { return 'divide-x divide-deep-blue-400 dark:divide-deep-blue-100' } else if (variant === 'subtle') { diff --git a/frontend/src/lib/components/common/button/model.ts b/frontend/src/lib/components/common/button/model.ts index 1a0922e5f8..eda59146c7 100644 --- a/frontend/src/lib/components/common/button/model.ts +++ b/frontend/src/lib/components/common/button/model.ts @@ -114,10 +114,10 @@ export namespace ButtonType { blue: { border: - 'border-luminance-blue-500 dark:border-luminance-blue-300 hover:border-luminance-blue-700 focus-visible:border-luminance-blue-700 bg-surface hover:bg-luminance-blue-100 dark:hover:bg-luminance-blue-900/40 focus-visible:bg-luminance-blue-100 focus-visible:dark:text-luminance-blue-100 dark:focus-visible:bg-luminance-blue-900 text-luminance-blue-500 dark:text-luminance-blue-300 dark:hover:text-luminance-blue-200 hover:text-luminance-blue-700 focus-visible:text-luminance-blue-700 focus-visible:ring-luminance-blue-300', + 'border-blue-500 dark:border-blue-300 hover:border-blue-700 focus-visible:border-blue-700 bg-surface hover:bg-blue-100 dark:hover:bg-blue-900/40 focus-visible:bg-blue-100 focus-visible:dark:text-blue-100 dark:focus-visible:bg-blue-900 text-blue-500 dark:text-blue-300 dark:hover:text-blue-200 hover:text-blue-700 focus-visible:text-blue-700 focus-visible:ring-blue-300', contained: - 'bg-luminance-blue-300 hover:bg-luminance-blue-400 focus-visible:bg-luminance-blue-500 text-white focus-visible:ring-luminance-blue-300', - divider: 'divide-x divide-luminance-blue-600' + 'bg-blue-300 hover:bg-blue-400 focus-visible:bg-blue-500 text-white focus-visible:ring-blue-300', + divider: 'divide-x divide-blue-600' }, marine: { border: @@ -173,13 +173,13 @@ export namespace ButtonType { export const VariantStyles: Record<'accent-secondary' | 'accent' | 'default' | 'subtle', string> = { 'accent-secondary': - 'bg-surface-accent-secondary hover:bg-surface-accent-secondary-hover focus-visible:bg-surface-accent-secondary-clicked text-white dark:text-deep-blue-900 focus-visible:ring-luminance-blue-300', + 'bg-surface-accent-secondary hover:bg-surface-accent-secondary-hover focus-visible:bg-surface-accent-secondary-clicked text-white dark:text-deep-blue-900 focus-visible:ring-blue-300', accent: - 'bg-surface-accent-primary hover:bg-surface-accent-hover focus-visible:bg-surface-accent-clicked text-white focus-visible:ring-luminance-blue-300', + 'bg-surface-accent-primary hover:bg-surface-accent-hover focus-visible:bg-surface-accent-clicked text-white focus-visible:ring-blue-300', default: - 'border border-border-light bg-transparent hover:bg-surface-hover text-primary focus-visible:bg-surface-hover focus-visible:ring-luminance-blue-300', + 'border border-border-light bg-transparent hover:bg-surface-hover text-primary focus-visible:bg-surface-hover focus-visible:ring-blue-300', subtle: - 'bg-transparent hover:bg-surface-hover text-primary focus-visible:bg-surface-hover focus-visible:ring-luminance-blue-300' + 'bg-transparent hover:bg-surface-hover text-primary focus-visible:bg-surface-hover focus-visible:ring-blue-300' } export const DestructiveVariantStyles: Record< diff --git a/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte b/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte index bdc900f3f8..23d91f790a 100644 --- a/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/ConfirmationModal.svelte @@ -69,7 +69,7 @@ Icon: RefreshCcw, color: 'dark', classes: { - icon: 'text-blue-500 dark:text-blue-400', + icon: 'text-blue-700 dark:text-blue-300', iconWrapper: 'bg-blue-100 dark:bg-blue-800/50' } } diff --git a/frontend/src/lib/components/graph/util.ts b/frontend/src/lib/components/graph/util.ts index 437e3f1352..8969f460c4 100644 --- a/frontend/src/lib/components/graph/util.ts +++ b/frontend/src/lib/components/graph/util.ts @@ -36,13 +36,13 @@ export function getNodeColorClasses(state: FlowNodeState, selected: boolean): Fl } satisfies Record let orangeStyle = { selected: { - bg: 'bg-orange-200 dark:bg-[#905036]', + bg: 'bg-orange-200 dark:bg-orange-700', outline: 'outline-orange-500' + outlined, text: 'text-orange-800 dark:text-orange-200', badge: 'bg-orange-100 text-orange-700' }, notSelected: { - bg: 'bg-orange-100 dark:bg-[#654338]', + bg: 'bg-orange-100 dark:bg-orange-800', outline: '', text: 'text-orange-700 dark:text-orange-300', badge: 'bg-orange-200 text-orange-700' @@ -60,7 +60,7 @@ export function getNodeColorClasses(state: FlowNodeState, selected: boolean): Fl _Skipped: { selected: defaultStyle.selected, notSelected: { - bg: 'bg-blue-100 dark:bg-[#2D3B63]', + bg: 'bg-blue-100 dark:bg-blue-950', outline: '', text: 'text-blue-600 dark:text-blue-200', badge: 'bg-blue-200 outline-border-selected text-blue-800' @@ -68,13 +68,13 @@ export function getNodeColorClasses(state: FlowNodeState, selected: boolean): Fl }, Success: { selected: { - bg: 'bg-green-200 dark:bg-[#329E6A]', + bg: 'bg-green-200 dark:bg-green-600', outline: 'outline-green-500 dark:outline-green-400' + outlined, text: 'text-green-800 dark:text-green-100', badge: 'bg-green-100 text-green-700' }, notSelected: { - bg: 'bg-green-100 dark:bg-[#3B7B5B]', + bg: 'bg-green-100 dark:bg-green-700', outline: '', text: 'text-green-700 dark:text-green-100', badge: 'bg-green-200 text-green-700' @@ -82,13 +82,13 @@ export function getNodeColorClasses(state: FlowNodeState, selected: boolean): Fl }, Failure: { selected: { - bg: 'bg-red-200 dark:bg-[#AA3E47]', + bg: 'bg-red-200 dark:bg-red-600', outline: 'outline-red-500' + outlined, text: 'text-red-800 dark:text-red-100', badge: 'bg-red-100 text-red-700' }, notSelected: { - bg: 'bg-red-100 dark:bg-[#81383F]', + bg: 'bg-red-100 dark:bg-red-700', outline: '', text: 'text-red-700 dark:text-red-200', badge: 'bg-red-200 text-red-700' @@ -98,13 +98,13 @@ export function getNodeColorClasses(state: FlowNodeState, selected: boolean): Fl WaitingForExecutor: orangeStyle, WaitingForEvents: { selected: { - bg: 'bg-purple-200 dark:bg-[#8243BB]', + bg: 'bg-purple-200 dark:bg-purple-600', outline: 'outline-purple-500' + outlined, text: 'text-purple-800 dark:text-purple-100', badge: 'bg-purple-100 text-purple-700' }, notSelected: { - bg: 'bg-purple-100 dark:bg-[#5F417E]', + bg: 'bg-purple-100 dark:bg-purple-700', outline: '', text: 'text-purple-700 dark:text-purple-200', badge: 'bg-purple-200 text-purple-700' diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs index a3540878ea..bb9d2ee3a3 100644 --- a/frontend/tailwind.config.cjs +++ b/frontend/tailwind.config.cjs @@ -110,17 +110,70 @@ const config = { 800: `rgb(${primitives['deep-blue-800']})`, 900: `rgb(${primitives['deep-blue-900']})` }, - 'luminance-blue': { - 50: `rgb(${primitives['luminance-blue-50']})`, - 100: `rgb(${primitives['luminance-blue-100']})`, - 200: `rgb(${primitives['luminance-blue-200']})`, - 300: `rgb(${primitives['luminance-blue-300']})`, - 400: `rgb(${primitives['luminance-blue-400']})`, - 500: `rgb(${primitives['luminance-blue-500']})`, - 600: `rgb(${primitives['luminance-blue-600']})`, - 700: `rgb(${primitives['luminance-blue-700']})`, - 800: `rgb(${primitives['luminance-blue-800']})`, - 900: `rgb(${primitives['luminance-blue-900']})` + red: { + 50: `rgb(${primitives['red-50']})`, + 100: `rgb(${primitives['red-100']})`, + 200: `rgb(${primitives['red-200']})`, + 300: `rgb(${primitives['red-300']})`, + 400: `rgb(${primitives['red-400']})`, + 500: `rgb(${primitives['red-500']})`, + 600: `rgb(${primitives['red-600']})`, + 700: `rgb(${primitives['red-700']})`, + 800: `rgb(${primitives['red-800']})`, + 900: `rgb(${primitives['red-900']})`, + 950: `rgb(${primitives['red-950']})` + }, + blue: { + 50: `rgb(${primitives['blue-50']})`, + 100: `rgb(${primitives['blue-100']})`, + 200: `rgb(${primitives['blue-200']})`, + 300: `rgb(${primitives['blue-300']})`, + 400: `rgb(${primitives['blue-400']})`, + 500: `rgb(${primitives['blue-500']})`, + 600: `rgb(${primitives['blue-600']})`, + 700: `rgb(${primitives['blue-700']})`, + 800: `rgb(${primitives['blue-800']})`, + 900: `rgb(${primitives['blue-900']})`, + 950: `rgb(${primitives['blue-950']})` + }, + green: { + 50: `rgb(${primitives['green-50']})`, + 100: `rgb(${primitives['green-100']})`, + 200: `rgb(${primitives['green-200']})`, + 300: `rgb(${primitives['green-300']})`, + 400: `rgb(${primitives['green-400']})`, + 500: `rgb(${primitives['green-500']})`, + 600: `rgb(${primitives['green-600']})`, + 700: `rgb(${primitives['green-700']})`, + 800: `rgb(${primitives['green-800']})`, + 900: `rgb(${primitives['green-900']})`, + 950: `rgb(${primitives['green-950']})` + }, + orange: { + 50: `rgb(${primitives['orange-50']})`, + 100: `rgb(${primitives['orange-100']})`, + 200: `rgb(${primitives['orange-200']})`, + 300: `rgb(${primitives['orange-300']})`, + 400: `rgb(${primitives['orange-400']})`, + 500: `rgb(${primitives['orange-500']})`, + 600: `rgb(${primitives['orange-600']})`, + 700: `rgb(${primitives['orange-700']})`, + 800: `rgb(${primitives['orange-800']})`, + 900: `rgb(${primitives['orange-900']})`, + 950: `rgb(${primitives['orange-950']})` + }, + purple: { + 50: `rgb(${primitives['purple-50']})`, + 100: `rgb(${primitives['purple-100']})`, + 200: `rgb(${primitives['purple-200']})`, + 300: `rgb(${primitives['purple-300']})`, + 400: `rgb(${primitives['purple-400']})`, + 500: `rgb(${primitives['purple-500']})`, + 600: `rgb(${primitives['purple-600']})`, + 700: `rgb(${primitives['purple-700']})`, + 800: `rgb(${primitives['purple-800']})`, + 900: `rgb(${primitives['purple-900']})`, + 950: `rgb(${primitives['purple-950']})` }, slate: { 50: '#f8fafc', @@ -170,18 +223,6 @@ const config = { 800: '#292524', 900: '#1c1917' }, - orange: { - 50: '#fff7ed', - 100: '#ffedd5', - 200: '#fed7aa', - 300: '#fdba74', - 400: '#fb923c', - 500: '#f97316', - 600: '#ea580c', - 700: '#c2410c', - 800: '#9a3412', - 900: '#7c2d12' - }, amber: { 50: '#fffbeb', 100: '#fef3c7', @@ -266,18 +307,6 @@ const config = { 800: '#5b21b6', 900: '#4c1d95' }, - purple: { - 50: '#faf5ff', - 100: '#f3e8ff', - 200: '#e9d5ff', - 300: '#d8b4fe', - 400: '#c084fc', - 500: '#a855f7', - 600: '#9333ea', - 700: '#7e22ce', - 800: '#6b21a8', - 900: '#581c87' - }, fuchsia: { 50: '#fdf4ff', 100: '#fae8ff', @@ -326,28 +355,6 @@ const config = { 800: '#1f2937', 900: '#111827' }, - red: { - 50: '#fef2f2', - 100: '#fee2e2', - 200: '#fecaca', - 300: '#fca5a5', - 400: '#f87171', - 500: '#ef4444', - 600: '#dc2626', - 700: '#b91c1c', - 800: '#991b1b', - 900: '#7f1d1d' - }, - orange: { - 100: '#ffedd5', - 200: '#ffedd5', - 300: '#FDC089', - 400: '#fb923c', - 500: '#f97316', - 600: '#ea580c', - 700: '#c2410c', - 800: '#c2410c' - }, yellow: { 50: '#fefce8', 100: '#fef9c3', @@ -360,31 +367,6 @@ const config = { 800: '#854d0e', 900: '#713f12' }, - green: { - 50: '#f0fdf4', - 100: '#dcfce7', - 200: '#bbf7d0', - 300: '#86efac', - 400: '#4ade80', - 500: '#22c55e', - 600: '#16a34a', - 700: '#15803d', - 800: '#166534', - 900: '#14532d' - }, - blue: { - 50: '#eff6ff', - 100: '#dbeafe', - 200: '#bfdbfe', - 300: '#93c5fd', - 400: '#60a5fa', - 500: '#3b82f6', - 600: '#2563eb', - 700: '#1d4ed8', - 800: '#1e40af', - 900: '#1e3a8a' - }, - indigo: { 50: '#eef2ff', 100: '#e0e7ff', From 1b88e0cf15e0e4a71851a832e2d05e16a20d6770 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:46:53 +0100 Subject: [PATCH 06/32] Migrate batch reruns pane to ui guidelines (#6946) * migrate batch reruns pane to ui guidelines * move relative class to ResizeTransitionWrapper --- .../InputTransformSchemaForm.svelte | 2 +- .../lib/components/ModulePreviewForm.svelte | 2 +- frontend/src/lib/components/SchemaForm.svelte | 3 +- .../common/ResizeTransitionWrapper.svelte | 2 +- .../runs/BatchReRunOptionsPane.svelte | 109 +++++++++--------- .../wizards/LoggedWizardResult.svelte | 2 +- 6 files changed, 62 insertions(+), 58 deletions(-) diff --git a/frontend/src/lib/components/InputTransformSchemaForm.svelte b/frontend/src/lib/components/InputTransformSchemaForm.svelte index 6770e24ce8..17e711c1f3 100644 --- a/frontend/src/lib/components/InputTransformSchemaForm.svelte +++ b/frontend/src/lib/components/InputTransformSchemaForm.svelte @@ -104,7 +104,7 @@ {#if keys.length > 0} {#each keys as argName, index (argName)} {#if (!filter || filter.includes(argName)) && Object.keys(schema.properties ?? {}).includes(argName)} - + diff --git a/frontend/src/lib/components/common/ResizeTransitionWrapper.svelte b/frontend/src/lib/components/common/ResizeTransitionWrapper.svelte index 3b53bb8980..b30017b63c 100644 --- a/frontend/src/lib/components/common/ResizeTransitionWrapper.svelte +++ b/frontend/src/lib/components/common/ResizeTransitionWrapper.svelte @@ -62,7 +62,7 @@ {#if currentResizeTransitionWrapper} {@render children()} {:else} -
+
{@render children()}
diff --git a/frontend/src/lib/components/runs/BatchReRunOptionsPane.svelte b/frontend/src/lib/components/runs/BatchReRunOptionsPane.svelte index 6095f086c1..b73a5a2eed 100644 --- a/frontend/src/lib/components/runs/BatchReRunOptionsPane.svelte +++ b/frontend/src/lib/components/runs/BatchReRunOptionsPane.svelte @@ -29,6 +29,8 @@ import Toggle from '../Toggle.svelte' import { TriangleAlert } from 'lucide-svelte' import { readFieldsRecursively } from '$lib/utils' + import Button from '../common/button/Button.svelte' + import ResizeTransitionWrapper from '../common/ResizeTransitionWrapper.svelte' let { selectedIds, @@ -158,7 +160,7 @@

Batch re-run options

-
+
{#await jobGroupsPromise then jobGroup} {#each jobGroup as group} - + {group.script_path} + ({jobGroupTotalCount(group)}) + {/each} {/await}
@@ -226,48 +229,50 @@
{#key [selected, displayedSchema]} {#each Object.keys(displayedSchema.properties) as propertyName} - { - if (!selected) return - const newArg = e.detail.arg as InputTransform - ;((options[selected.kind][selected.script_path] ??= {}).input_transforms ??= - {})[propertyName] = newArg - }} - argName={propertyName} - schema={displayedSchema} - {extraLib} - previousModuleId={undefined} - pickableProperties={{ - hasResume: false, - previousId: undefined, - priorIds: {}, - flow_input: {} - }} - hideHelpButton - {...propertyAlwaysExists(propertyName, selected) - ? {} - : { - headerTooltip: - 'This property does not exist on all versions of the script. You can handle different cases in the code below', - HeaderTooltipIcon: TriangleAlert, - headerTooltipIconClass: 'text-orange-500' - }} - {...propertyAlwaysHasSameType(propertyName, selected) - ? {} - : { - headerTooltip: - 'This property does not always have the same type depending on the version of the script. You can handle different cases in the code below', - HeaderTooltipIcon: TriangleAlert, - headerTooltipIconClass: 'text-orange-500' - }} - /> + + { + if (!selected) return + const newArg = e.detail.arg as InputTransform + ;((options[selected.kind][selected.script_path] ??= {}).input_transforms ??= + {})[propertyName] = newArg + }} + argName={propertyName} + schema={displayedSchema} + {extraLib} + previousModuleId={undefined} + pickableProperties={{ + hasResume: false, + previousId: undefined, + priorIds: {}, + flow_input: {} + }} + hideHelpButton + {...propertyAlwaysExists(propertyName, selected) + ? {} + : { + headerTooltip: + 'This property does not exist on all versions of the script. You can handle different cases in the code below', + HeaderTooltipIcon: TriangleAlert, + headerTooltipIconClass: 'text-orange-500' + }} + {...propertyAlwaysHasSameType(propertyName, selected) + ? {} + : { + headerTooltip: + 'This property does not always have the same type depending on the version of the script. You can handle different cases in the code below', + HeaderTooltipIcon: TriangleAlert, + headerTooltipIconClass: 'text-orange-500' + }} + /> + {/each} {/key}
diff --git a/frontend/src/lib/components/wizards/LoggedWizardResult.svelte b/frontend/src/lib/components/wizards/LoggedWizardResult.svelte index d37c2b7f26..be82f0b82e 100644 --- a/frontend/src/lib/components/wizards/LoggedWizardResult.svelte +++ b/frontend/src/lib/components/wizards/LoggedWizardResult.svelte @@ -91,7 +91,7 @@ /> {/if} - + {#if descriptionOpened}
Date: Mon, 27 Oct 2025 16:47:28 +0100 Subject: [PATCH 07/32] Runs page hide right panel (#6949) * Hide right runs panel when not selected * AnimatedPane * nits --- .../components/splitPanes/AnimatedPane.svelte | 57 +++++++++++++++++++ .../(logged)/runs/[...path]/+page.svelte | 9 ++- 2 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 frontend/src/lib/components/splitPanes/AnimatedPane.svelte diff --git a/frontend/src/lib/components/splitPanes/AnimatedPane.svelte b/frontend/src/lib/components/splitPanes/AnimatedPane.svelte new file mode 100644 index 0000000000..d4f19471e9 --- /dev/null +++ b/frontend/src/lib/components/splitPanes/AnimatedPane.svelte @@ -0,0 +1,57 @@ + + + computedSize, (v) => (userChangedSize = v)}> + {@render children()} + diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte index 0ccba41b67..743cb81dd4 100644 --- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte @@ -48,6 +48,7 @@ import { createBubbler } from 'svelte/legacy' import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte' + import AnimatedPane from '$lib/components/splitPanes/AnimatedPane.svelte' let jobs: Job[] | undefined = $state() let selectedIds: string[] = $state([]) @@ -1157,7 +1158,7 @@
- +
- + 0}> {#if selectionMode === 're-run'} {:else if selectedIds.length === 1} @@ -1314,10 +1315,8 @@
There are {selectedIds.length} jobs selected. Choose 1 to see detailed information
- {:else} -
No job selected
{/if} -
+
From d45f542739b0efbfd410cf6950505198e191dc53 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:48:39 +0100 Subject: [PATCH 08/32] nit prose a color (#6951) --- frontend/src/lib/assets/app.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/lib/assets/app.css b/frontend/src/lib/assets/app.css index 6f5d25b384..cdccc1a865 100644 --- a/frontend/src/lib/assets/app.css +++ b/frontend/src/lib/assets/app.css @@ -62,6 +62,9 @@ list-style-type: '- '; padding-left: 3rem; } + .prose a { + @apply text-accent no-underline; + } .autocomplete-list-item-create { @apply !text-primary-inverse !bg-surface-inverse; From 603cd73b707b71447bc1ab3ffd1309e0b6d6ca5d Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:48:59 +0100 Subject: [PATCH 09/32] nit fix ci (#6956) --- .../components/FlowHistoryJobPicker.svelte | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/frontend/src/lib/components/FlowHistoryJobPicker.svelte b/frontend/src/lib/components/FlowHistoryJobPicker.svelte index 891df97e1b..a2be0d5d0f 100644 --- a/frontend/src/lib/components/FlowHistoryJobPicker.svelte +++ b/frontend/src/lib/components/FlowHistoryJobPicker.svelte @@ -7,10 +7,10 @@ import { JobService } from '$lib/gen' interface Props { - path: string; - selected?: string | undefined; - selectInitial?: boolean; - loading?: boolean; + path: string + selected?: string | undefined + selectInitial?: boolean + loading?: boolean } let { @@ -18,7 +18,7 @@ selected = undefined, selectInitial = false, loading = $bindable(false) - }: Props = $props(); + }: Props = $props() const dispatch = createEventDispatcher() async function loadInitial() { @@ -27,7 +27,6 @@ workspace: $workspaceStore!, scriptPathExact: path, jobKinds: ['flow', 'flowpreview'].join(','), - page: 1, perPage: 1 }) if (jobs.length > 0) { @@ -42,31 +41,27 @@ $effect(() => { $workspaceStore && untrack(() => loadInitial()) - }); + }) {#snippet trigger()} - - - + {/snippet} {#snippet content()} - -
- { - if (e.detail) { - dispatch('select', { jobId: e.detail?.jobId, initial: false }) - } else { - dispatch('unselect') - } - }} - {selected} - runnableId={path} - runnableType={'FlowPath'} - /> -
- +
+ { + if (e.detail) { + dispatch('select', { jobId: e.detail?.jobId, initial: false }) + } else { + dispatch('unselect') + } + }} + {selected} + runnableId={path} + runnableType={'FlowPath'} + /> +
{/snippet}
From f33ae2a4b1157d2371f6ae4730e16b16dcad29d5 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:49:27 +0100 Subject: [PATCH 10/32] Remove whitespace-nowrap from Button (#6955) --- frontend/src/lib/components/CronInput.svelte | 2 +- .../src/lib/components/ErrorOrRecoveryHandler.svelte | 2 +- frontend/src/lib/components/InstanceSetting.svelte | 5 +++-- frontend/src/lib/components/ScriptBuilder.svelte | 12 +++++------- .../components/apps/editor/AppEditorHeader.svelte | 2 +- .../apps/editor/componentsPanel/CssSettings.svelte | 2 +- .../src/lib/components/common/button/Button.svelte | 4 ++-- .../flows/content/FlowModuleComponent.svelte | 2 +- .../flows/content/FlowModuleTimeout.svelte | 2 +- .../lib/components/flows/content/FlowSettings.svelte | 5 +++-- .../flows/header/FlowPreviewButtons.svelte | 1 + .../lib/components/settings/UserInfoSettings.svelte | 7 +++++-- .../components/settings/WorkspaceUserSettings.svelte | 2 +- .../triggers/email/DefaultEmailConfigSection.svelte | 2 +- .../triggers/schedules/ScheduleEditorInner.svelte | 2 +- .../triggers/webhook/WebhooksConfigSection.svelte | 2 +- .../workspaceSettings/DucklakeSettings.svelte | 4 ++-- .../workspaceSettings/StorageSettings.svelte | 4 ++-- 18 files changed, 33 insertions(+), 29 deletions(-) diff --git a/frontend/src/lib/components/CronInput.svelte b/frontend/src/lib/components/CronInput.svelte index 33ef38d08d..b7febcdaca 100644 --- a/frontend/src/lib/components/CronInput.svelte +++ b/frontend/src/lib/components/CronInput.svelte @@ -217,7 +217,7 @@ error={!validCRON} /> {#if !disabled} -
+
{@render cronBuilder()}
diff --git a/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte b/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte index 770e5407a6..57713e9eb4 100644 --- a/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte +++ b/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte @@ -345,7 +345,7 @@ {#if !handlerPath} Set password
{#if passwordError} diff --git a/frontend/src/lib/components/settings/WorkspaceUserSettings.svelte b/frontend/src/lib/components/settings/WorkspaceUserSettings.svelte index 2137e23bce..6d36e31d4b 100644 --- a/frontend/src/lib/components/settings/WorkspaceUserSettings.svelte +++ b/frontend/src/lib/components/settings/WorkspaceUserSettings.svelte @@ -313,7 +313,7 @@ documentationLink="https://www.windmill.dev/docs/core_concepts/authentification" /> -
+
diff --git a/frontend/src/lib/components/triggers/email/DefaultEmailConfigSection.svelte b/frontend/src/lib/components/triggers/email/DefaultEmailConfigSection.svelte index 6e3702ba87..0ed7d5b4ae 100644 --- a/frontend/src/lib/components/triggers/email/DefaultEmailConfigSection.svelte +++ b/frontend/src/lib/components/triggers/email/DefaultEmailConfigSection.svelte @@ -58,7 +58,7 @@
{#if SCRIPT_VIEW_SHOW_CREATE_TOKEN_BUTTON}