diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 45b32a0b3f..85fdbdafa0 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -5,7 +5,7 @@ use chrono::Timelike; #[cfg(feature = "enterprise")] use futures::StreamExt; -use futures::{stream, Stream}; +use futures::{stream, Stream, StreamExt}; use serde::Deserialize; use serde_json::json; use sqlx::{postgres::PgListener, types::Uuid, Pool, Postgres}; @@ -15,7 +15,7 @@ use tokio::sync::RwLock; use tokio::time::{timeout, Duration}; use windmill_api_client::types::{ - CreateFlowBody, RawScript + CreateFlowBody, RawScript, NewScript, NewScriptLanguage }; #[cfg(feature = "enterprise")] @@ -2925,7 +2925,7 @@ async fn run_deployed_relative_imports(db: &Pool, script_content: Stri completed.next().await; // deployed script let script = - query!("SELECT hash FROM script WHERE path = $1", "f/system/test_import".to_string()) + sqlx::query!("SELECT hash FROM script WHERE path = $1", "f/system/test_import".to_string()) .fetch_one(&db2) .await .unwrap(); diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index b3b3fd77fa..2ea6c4f1bf 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -4117,6 +4117,7 @@ paths: - $ref: "#/components/parameters/StartedBefore" - $ref: "#/components/parameters/StartedAfter" - $ref: "#/components/parameters/CreatedOrStartedBefore" + - $ref: "#/components/parameters/Running" - $ref: "#/components/parameters/CreatedOrStartedAfter" - $ref: "#/components/parameters/JobKinds" - $ref: "#/components/parameters/ArgsFilter" diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 2457e543a9..3e60a2acd6 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -780,7 +780,14 @@ async fn list_jobs( let (per_page, offset) = paginate(pagination); let lqc = lq.clone(); - let sqlc = list_completed_jobs_query( + 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(), + )); + + } + let sqlc = if lq.running.is_none() { + Some(list_completed_jobs_query( &w_id, per_page + offset, 0, @@ -817,7 +824,10 @@ async fn list_jobs( "null as concurrent_limit", "null as concurrency_time_window_s", ], - ); + )) + } else { + None + }; let sql = if lq.success.is_none() { let sqlq = list_queue_jobs_query( @@ -833,7 +843,7 @@ async fn list_jobs( created_after: lq.created_after, created_or_started_before: lq.created_or_started_before, created_or_started_after: lq.created_or_started_after, - running: None, + running: lq.running, parent_job: lq.parent_job, order_desc: Some(true), job_kinds: lq.job_kinds, @@ -876,6 +886,7 @@ async fn list_jobs( ], ); + if let Some(sqlc) = sqlc { format!( "{} UNION ALL {} LIMIT {} OFFSET {};", &sqlq.subquery()?, @@ -883,8 +894,11 @@ async fn list_jobs( per_page, offset ) + } else { + sqlq.query()? + } } else { - sqlc.query()? + sqlc.unwrap().query()? }; let mut tx = user_db.begin(&authed).await?; let jobs: Vec = sqlx::query_as(&sql).fetch_all(&mut *tx).await?; @@ -2721,6 +2735,7 @@ pub struct ListCompletedQuery { pub created_or_started_before: Option>, pub created_or_started_after: Option>, pub success: Option, + pub running: Option, pub parent_job: Option, pub order_desc: Option, pub job_kinds: Option, diff --git a/frontend/src/lib/components/OAuthSetting.svelte b/frontend/src/lib/components/OAuthSetting.svelte index 8de1c5b07c..76ec51f73a 100644 --- a/frontend/src/lib/components/OAuthSetting.svelte +++ b/frontend/src/lib/components/OAuthSetting.svelte @@ -7,11 +7,10 @@ export let value: any export let login = true - $: if (value && value?.['allowed_domains'] == undefined) { - value = { ...(value ?? {}), allowed_domains: [] } - } - $: enabled = value != undefined + + + let allowed_domains = value?.['allowed_domains'] ?? ''
@@ -39,14 +38,19 @@ {#if login} {/if} {#if name == 'google'} @@ -83,3 +87,4 @@
{/if} + diff --git a/frontend/src/lib/components/runs/RunsFilter.svelte b/frontend/src/lib/components/runs/RunsFilter.svelte index cf16b8cf85..a132bd1805 100644 --- a/frontend/src/lib/components/runs/RunsFilter.svelte +++ b/frontend/src/lib/components/runs/RunsFilter.svelte @@ -10,7 +10,7 @@ // Filters export let path: string | null = null - export let success: boolean | undefined = undefined + export let success: "running" | "success" | "failure" | undefined = undefined export let isSkipped: boolean | undefined = undefined export let argFilter: string export let argError: string @@ -187,8 +187,9 @@ Status - - + + +
diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte index 1f4da44c9e..f5135302ed 100644 --- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte @@ -42,10 +42,7 @@ let user: string | null = $page.url.searchParams.get('user') let folder: string | null = $page.url.searchParams.get('folder') // Rest of filters handled by RunsFilter - let success: boolean | undefined = - $page.url.searchParams.get('success') != undefined - ? $page.url.searchParams.get('success') == 'true' - : undefined + let success: "running" | "success" | "failure" | undefined = ($page.url.searchParams.get('success') ?? undefined) as "running" | "success" | "failure" | undefined let isSkipped: boolean | undefined = $page.url.searchParams.get('is_skipped') != undefined ? $page.url.searchParams.get('is_skipped') == 'true' @@ -128,7 +125,8 @@ createdBy: user === null || user === '' ? undefined : user, scriptPathStart: folder === null || folder === '' ? undefined : `f/${folder}/`, jobKinds, - success, + success: success == "success" ? true : (success == 'failure' ? false : undefined), + running: success == 'running' ? true : undefined, isSkipped, isFlowStep: jobKindsCat != 'all' ? false : undefined, args: @@ -166,34 +164,38 @@ async function syncer() { getCount() if (sync && jobs && maxTs == undefined) { - let ts: string | undefined = undefined - let cursor = 0 - while (cursor < jobs.length && minTs == undefined) { - let invCursor = jobs.length - 1 - cursor - let isQueuedJob = cursor == jobs?.length - 1 || jobs[invCursor].type == Job.type.QUEUED_JOB - if (isQueuedJob) { - if (cursor > 0) { - const date = new Date(jobs[invCursor + 1]?.created_at!) - date.setMilliseconds(date.getMilliseconds() + 1) - ts = date.toISOString() + if (success == 'running') { + loadJobs() + } else { + let ts: string | undefined = undefined + let cursor = 0 + while (cursor < jobs.length && minTs == undefined) { + let invCursor = jobs.length - 1 - cursor + let isQueuedJob = cursor == jobs?.length - 1 || jobs[invCursor].type == Job.type.QUEUED_JOB + if (isQueuedJob) { + if (cursor > 0) { + const date = new Date(jobs[invCursor + 1]?.created_at!) + date.setMilliseconds(date.getMilliseconds() + 1) + ts = date.toISOString() + } + break } - break + cursor++ } - cursor++ - } - loading = true - const newJobs = await fetchJobs(maxTs, minTs ?? ts) - if (newJobs && newJobs.length > 0 && jobs) { - const oldJobs = jobs?.map((x) => x.id) - jobs = newJobs.filter((x) => !oldJobs.includes(x.id)).concat(jobs) - newJobs - .filter((x) => oldJobs.includes(x.id)) - .forEach((x) => (jobs![jobs?.findIndex((y) => y.id == x.id)!] = x)) - jobs = jobs - computeCompletedJobs() + loading = true + const newJobs = await fetchJobs(maxTs, minTs ?? ts) + if (newJobs && newJobs.length > 0 && jobs) { + const oldJobs = jobs?.map((x) => x.id) + jobs = newJobs.filter((x) => !oldJobs.includes(x.id)).concat(jobs) + newJobs + .filter((x) => oldJobs.includes(x.id)) + .forEach((x) => (jobs![jobs?.findIndex((y) => y.id == x.id)!] = x)) + jobs = jobs + computeCompletedJobs() + } + loading = false } - loading = false } } @@ -204,10 +206,7 @@ path = $page.params.path user = $page.url.searchParams.get('user') folder = $page.url.searchParams.get('folder') - success = - $page.url.searchParams.get('success') != undefined - ? $page.url.searchParams.get('success') == 'true' - : undefined + success = ($page.url.searchParams.get('success') ?? undefined) as "success" | "failure" | "running" | undefined isSkipped = $page.url.searchParams.get('is_skipped') != undefined ? $page.url.searchParams.get('is_skipped') == 'true'