From 48d87ab12cb18ab9e26d8ea2afc3b47354dc4532 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 10 Jan 2023 08:24:29 +0100 Subject: [PATCH] various improvements --- backend/sqlx-data.json | 69 ++++++++--- backend/windmill-api/openapi.yaml | 50 +++++++- backend/windmill-api/src/flows.rs | 19 +++ backend/windmill-api/src/jobs.rs | 22 +++- backend/windmill-api/src/oauth2.rs | 15 ++- backend/windmill-api/src/scripts.rs | 19 +++ backend/windmill-queue/src/jobs.rs | 16 +++ frontend/src/lib/components/ArgInput.svelte | 43 +++++-- frontend/src/lib/components/Dropdown.svelte | 3 +- frontend/src/lib/components/EditorBar.svelte | 4 +- frontend/src/lib/components/ItemPicker.svelte | 10 +- .../src/lib/components/ModulePreview.svelte | 2 +- frontend/src/lib/components/RunForm.svelte | 6 +- frontend/src/lib/components/SchemaForm.svelte | 10 +- .../apps/components/form/AppForm.svelte | 5 +- .../apps/components/helpers/InputValue.svelte | 1 + .../helpers/RunnableComponent.svelte | 5 +- .../components/helpers/RunnableWrapper.svelte | 2 + .../numberInputs/AppSliderInputs.svelte | 2 +- .../components/apps/editor/GridEditor.svelte | 1 - .../settingsPanel/ComponentPanel.svelte | 5 +- .../settingsPanel/InputsSpecsEditor.svelte | 9 +- .../editor/settingsPanel/TableActions.svelte | 2 +- .../inputEditor/RowInputEditor.svelte | 2 +- .../inputEditor/RunnableInputEditor.svelte | 3 +- .../mainInput/RunnableSelector.svelte | 7 +- .../src/lib/components/apps/editorUtils.ts | 8 +- frontend/src/lib/components/apps/utils.ts | 7 +- .../components/common/button/Button.svelte | 2 +- .../common/table/LanguageBadge.svelte | 4 +- .../lib/components/common/table/Row.svelte | 8 +- .../components/flows/CreateActionsApp.svelte | 4 +- .../components/flows/CreateActionsFlow.svelte | 2 +- .../lib/components/home/ListFilters.svelte | 5 + .../scripts/CreateActionsScript.svelte | 2 +- .../src/routes/(root)/(logged)/+page.svelte | 3 +- .../(logged)/flows/get/[...path]/+page.svelte | 3 + .../(logged)/flows/run/[...path]/+page.svelte | 4 + .../(root)/(logged)/run/[...run]/+page.svelte | 37 +++--- .../(logged)/runs/[...path]/+page.svelte | 113 ++++++++---------- .../scripts/get/[...hash]/+page.svelte | 5 + .../scripts/run/[...hash]/+page.svelte | 4 + 42 files changed, 375 insertions(+), 168 deletions(-) diff --git a/backend/sqlx-data.json b/backend/sqlx-data.json index 793e407a4e..4d32447245 100644 --- a/backend/sqlx-data.json +++ b/backend/sqlx-data.json @@ -1465,6 +1465,26 @@ }, "query": "UPDATE app SET versions = array_append(versions, $1) WHERE id = $2" }, + "42e1b5634a9e51247115fa73f85a97b1467c913d012cac9c45bb6a349082dc71": { + "describe": { + "columns": [ + { + "name": "path", + "ordinal": 0, + "type_info": "Varchar" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "SELECT distinct(path) FROM flow WHERE workspace_id = $1" + }, "438fb925ee90d5115bd3c3be8ae48b56ba86017af3ca519bd3a15829edaa7d1b": { "describe": { "columns": [ @@ -2790,20 +2810,6 @@ }, "query": "SELECT workspace_id, name, display_name, owners, extra_perms FROM folder WHERE workspace_id = $1 ORDER BY name desc LIMIT $2 OFFSET $3" }, - "877829f87c4d94c2e385ab9c5d75d3f70929c89231650e20db57c4b7c1d8911f": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Left": [ - "Varchar", - "Varchar", - "Text" - ] - } - }, - "query": "INSERT INTO group_\n (workspace_id, name, summary)\n VALUES ($1, $2, $3) ON CONFLICT DO NOTHING" - }, "8876fa929ffb175cd976a2bca1195704aa9fe7215013ae29e49ef15cb201ba57": { "describe": { "columns": [], @@ -4928,6 +4934,21 @@ }, "query": "SELECT count(path) FROM app WHERE path LIKE 'f/' || $1 || '%' AND workspace_id = $2" }, + "d444e1c1e12a82e9aee5c2ffc4d1d3841bd41dd71344ab155c9842b45bcf30b6": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "VarcharArray", + "Jsonb" + ] + } + }, + "query": "INSERT INTO folder\n (workspace_id, name, owners, extra_perms)\n VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING" + }, "d47bff7d6b54cd6da8bb330f7321c37af5dcbd76f9acad73b5ba1b8a4afb5091": { "describe": { "columns": [ @@ -5763,6 +5784,26 @@ }, "query": "UPDATE queue SET canceled = true, canceled_by = $1, canceled_reason = $2, scheduled_for = now(), suspend = 0 WHERE id = $3 AND workspace_id = $4 RETURNING id" }, + "f2485c69b3ab6bec11c4e1eac2934d6e49f83b71a72fe74eba7b49abc225df7c": { + "describe": { + "columns": [ + { + "name": "path", + "ordinal": 0, + "type_info": "Varchar" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "SELECT distinct(path) FROM script WHERE workspace_id = $1" + }, "f325a1262084bd3468e12dc8bcc289a96536f172b679af54dd0fbc82d4d7c987": { "describe": { "columns": [], diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 84be3c1387..6a3080f6c6 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -2004,6 +2004,25 @@ paths: items: $ref: "#/components/schemas/Script" + /w/{workspace}/scripts/list_paths: + get: + summary: list all available scripts paths + operationId: listScriptPaths + tags: + - script + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: list of script paths + content: + text/plain: + schema: + type: array + items: + type: string + + /w/{workspace}/scripts/create: post: summary: create script @@ -2411,6 +2430,24 @@ paths: application/json: schema: {} + /w/{workspace}/flows/list_paths: + get: + summary: list all available flow paths + operationId: listFlowPaths + tags: + - flow + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: list of flow paths + content: + text/plain: + schema: + type: array + items: + type: string + /w/{workspace}/flows/list: get: summary: list all available flows @@ -2986,7 +3023,8 @@ paths: - $ref: "#/components/parameters/CreatedAfter" - $ref: "#/components/parameters/Success" - $ref: "#/components/parameters/JobKinds" - - $ref: "#/components/parameters/Suspend" + - $ref: "#/components/parameters/Suspended" + - $ref: "#/components/parameters/Running" responses: "200": description: All available queued jobs @@ -4419,12 +4457,18 @@ components: in: query schema: type: boolean - Suspend: - name: suspend + Suspended: + name: suspended description: filter on suspended jobs in: query schema: type: boolean + Running: + name: running + description: filter on running jobs + in: query + schema: + type: boolean After: name: after description: filter on created after (exclusive) timestamp diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index b528a232ad..90440797c4 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -42,6 +42,7 @@ pub fn workspaced_service() -> Router { .route("/archive/*path", post(archive_flow_by_path)) .route("/get/*path", get(get_flow_by_path)) .route("/exists/*path", get(exists_flow_by_path)) + .route("/list_paths", get(list_paths)) } pub fn global_service() -> Router { @@ -122,6 +123,24 @@ async fn list_hub_flows( Ok(Json(flows)) } +async fn list_paths( + authed: Authed, + Extension(user_db): Extension, + Path(w_id): Path, +) -> JsonResult> { + let mut tx = user_db.begin(&authed).await?; + + let flows = sqlx::query_scalar!( + "SELECT distinct(path) FROM flow WHERE workspace_id = $1", + w_id + ) + .fetch_all(&mut tx) + .await?; + tx.commit().await?; + + Ok(Json(flows)) +} + pub async fn get_hub_flow_by_id( Authed { email, .. }: Authed, Path(id): Path, diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 4e46abb110..f5a2d35277 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -215,28 +215,40 @@ pub async fn get_job_by_id<'c>( pub struct CompletedJob { pub workspace_id: String, pub id: Uuid, + #[serde(skip_serializing_if = "Option::is_none")] pub parent_job: Option, pub created_by: String, pub created_at: chrono::DateTime, pub started_at: chrono::DateTime, pub duration_ms: i32, pub success: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub script_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub script_path: Option, pub args: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub result: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub logs: Option, pub deleted: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub raw_code: Option, pub canceled: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub canceled_by: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub canceled_reason: Option, pub job_kind: JobKind, + #[serde(skip_serializing_if = "Option::is_none")] pub schedule_path: Option, pub permissioned_as: String, + #[serde(skip_serializing_if = "Option::is_none")] pub flow_status: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub raw_flow: Option, pub is_flow_step: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub language: Option, pub is_skipped: bool, pub email: String, @@ -336,6 +348,7 @@ fn list_queue_jobs_query(w_id: &str, lq: &ListQueueQuery, fields: &[&str]) -> Sq if let Some(dt) = &lq.created_after { sqlb.and_where_gt("created_at", format!("to_timestamp({})", dt.timestamp())); } + if let Some(s) = &lq.suspended { if *s { sqlb.and_where_gt("suspend", 0); @@ -451,7 +464,6 @@ async fn list_jobs( "job_kind", "schedule_path", "permissioned_as", - "flow_status", "is_flow_step", "language", "false as is_skipped", @@ -486,7 +498,6 @@ async fn list_jobs( "job_kind", "schedule_path", "permissioned_as", - "flow_status", "is_flow_step", "language", "is_skipped", @@ -964,7 +975,6 @@ struct UnifiedJob { job_kind: JobKind, schedule_path: Option, permissioned_as: String, - flow_status: Option, is_flow_step: bool, language: Option, is_skipped: bool, @@ -990,6 +1000,7 @@ impl From for Job { args: uj.args, result: None, logs: None, + flow_status: None, deleted: uj.deleted, canceled: uj.canceled, canceled_by: uj.canceled_by, @@ -998,7 +1009,6 @@ impl From for Job { job_kind: uj.job_kind, schedule_path: uj.schedule_path, permissioned_as: uj.permissioned_as, - flow_status: uj.flow_status, raw_flow: None, is_flow_step: uj.is_flow_step, language: uj.language, @@ -1019,6 +1029,7 @@ impl From for Job { running: uj.running.unwrap(), scheduled_for: uj.scheduled_for.unwrap(), logs: None, + flow_status: None, raw_code: None, raw_lock: None, canceled: uj.canceled, @@ -1028,7 +1039,6 @@ impl From for Job { job_kind: uj.job_kind, schedule_path: uj.schedule_path, permissioned_as: uj.permissioned_as, - flow_status: uj.flow_status, raw_flow: None, is_flow_step: uj.is_flow_step, language: uj.language, @@ -1621,7 +1631,7 @@ async fn delete_completed_job( require_admin(authed.is_admin, &authed.username)?; let job_o = sqlx::query_as::<_, CompletedJob>( - "UPDATE completed_job SET logs = '', deleted = true WHERE id = $1 AND workspace_id = $2 \ + "UPDATE completed_job SET logs = '', result = null, deleted = true WHERE id = $1 AND workspace_id = $2 \ RETURNING *", ) .bind(id) diff --git a/backend/windmill-api/src/oauth2.rs b/backend/windmill-api/src/oauth2.rs index 17a58b9cf4..81cee619b7 100644 --- a/backend/windmill-api/src/oauth2.rs +++ b/backend/windmill-api/src/oauth2.rs @@ -656,19 +656,18 @@ async fn connect_slack_callback( .execute(&mut tx) .await?; sqlx::query!( - "INSERT INTO group_ - (workspace_id, name, summary) - VALUES ($1, $2, $3) ON CONFLICT DO NOTHING", + "INSERT INTO folder + (workspace_id, name, owners, extra_perms) + VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", &w_id, - "slack", - "The group that runs the script triggered by the slack /windmill command. - Share scripts to this group to make them executable from slack and add - members to this group to let them manage the slack related owner space." + "slack_bot", + &[], + serde_json::json!({}) ) .execute(&mut tx) .await?; - let token_path = "g/slack/bot_token"; + let token_path = "f/slack_bot/bot_token"; let mc = build_crypt(&mut tx, &w_id).await?; let value = encrypt(&mc, &token.bot.bot_access_token); sqlx::query!( diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index 4c5d8be3e7..d9280a6c4c 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -72,6 +72,7 @@ pub fn workspaced_service() -> Router { .route("/get/h/:hash", get(get_script_by_hash)) .route("/raw/h/:hash", get(raw_script_by_hash)) .route("/deployment_status/h/:hash", get(get_deployment_status)) + .route("/list_paths", get(list_paths)) } async fn list_scripts( authed: Authed, @@ -464,6 +465,24 @@ async fn get_script_by_path( Ok(Json(script)) } +async fn list_paths( + authed: Authed, + Extension(user_db): Extension, + Path(w_id): Path, +) -> JsonResult> { + let mut tx = user_db.begin(&authed).await?; + + let scripts = sqlx::query_scalar!( + "SELECT distinct(path) FROM script WHERE workspace_id = $1", + w_id + ) + .fetch_all(&mut tx) + .await?; + tx.commit().await?; + + Ok(Json(scripts)) +} + async fn raw_script_by_path( authed: Authed, Extension(user_db): Extension, diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 6327199943..fbe741e0f0 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -571,33 +571,49 @@ pub async fn get_hub_script(path: String, email: &str) -> error::Result, pub created_by: String, pub created_at: chrono::DateTime, + #[serde(skip_serializing_if = "Option::is_none")] pub started_at: Option>, pub scheduled_for: chrono::DateTime, pub running: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub script_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub script_path: Option, pub args: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub logs: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub raw_code: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub raw_lock: Option, pub canceled: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub canceled_by: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub canceled_reason: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub last_ping: Option>, pub job_kind: JobKind, + #[serde(skip_serializing_if = "Option::is_none")] pub schedule_path: Option, pub permissioned_as: String, + #[serde(skip_serializing_if = "Option::is_none")] pub flow_status: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub raw_flow: Option, pub is_flow_step: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub language: Option, pub same_worker: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub pre_run_error: Option, pub email: String, pub visible_to_owner: bool, + #[serde(skip_serializing_if = "Option::is_none")] pub suspend: Option, } diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index 009ec4da95..e66ef1d4b5 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -158,7 +158,7 @@ $: inputCat = computeInputCat(type, format, itemsType?.type, enum_, contentEncoding) -
+
{#if displayHeader} @@ -229,7 +229,10 @@ {:else} { + window.dispatchEvent(new Event('pointerup')) + dispatch('focus') + }} {disabled} type="number" class={valid @@ -321,7 +324,10 @@ {:else}