diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index e515b52d4f..7721124438 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -11054,7 +11054,7 @@ components: ] kind: type: string - enum: [script, failure, trigger, command, approval] + enum: [script, failure, trigger, command, approval, preprocessor] starred: type: boolean tag: @@ -11160,7 +11160,7 @@ components: ] kind: type: string - enum: [script, failure, trigger, command, approval] + enum: [script, failure, trigger, command, approval, preprocessor] tag: type: string draft_only: diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index bec8c3b2c8..10ac5aa387 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -28,6 +28,7 @@ use axum::{ Json, Router, }; use hyper::StatusCode; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use serde_json::json; use serde_json::value::RawValue; @@ -238,7 +239,19 @@ async fn list_scripts( .limit(per_page) .clone(); - if !lq.include_without_main.unwrap_or(false) || authed.is_operator { + let lowercased_kinds: Option> = lq + .kinds + .map(|x| x.split(",").map(&str::to_lowercase).collect()); + + if (!lq.include_without_main.unwrap_or(false) + && lowercased_kinds + .as_ref() + .map(|x| !x.contains(&"preprocessor".to_string())) + .unwrap_or(true)) + || authed.is_operator + { + // only include scripts that have a main function + // do not hide scripts without main if preprocessor is in the kinds sqlb.and_where("o.no_main_func IS NOT TRUE"); } @@ -278,14 +291,13 @@ async fn list_scripts( if let Some(it) = &lq.is_template { sqlb.and_where_eq("is_template", it); } - if let Some(kinds_val) = &lq.kinds { - let lowercased_kinds: Vec = kinds_val - .split(",") - .map(&str::to_lowercase) + if let Some(lowercased_kinds) = lowercased_kinds { + let safe_kinds = lowercased_kinds + .into_iter() .map(sql_builder::quote) - .collect(); - if lowercased_kinds.len() > 0 { - sqlb.and_where_in("kind", lowercased_kinds.as_slice()); + .collect_vec(); + if safe_kinds.len() > 0 { + sqlb.and_where_in("kind", safe_kinds.as_slice()); } } if lq.starred_only.unwrap_or(false) { diff --git a/backend/windmill-common/src/scripts.rs b/backend/windmill-common/src/scripts.rs index 11c4aa01d4..6f33f2efe5 100644 --- a/backend/windmill-common/src/scripts.rs +++ b/backend/windmill-common/src/scripts.rs @@ -128,6 +128,7 @@ pub enum ScriptKind { Failure, Script, Approval, + Preprocessor, } impl Display for ScriptKind { @@ -137,6 +138,7 @@ impl Display for ScriptKind { ScriptKind::Failure => "failure", ScriptKind::Script => "script", ScriptKind::Approval => "approval", + ScriptKind::Preprocessor => "preprocessor", })?; Ok(()) } diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index c63d52996e..f3dcdea4e0 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -43,6 +43,7 @@ Rocket, Save, Settings, + Shuffle, X } from 'lucide-svelte' import { sendUserToast } from '$lib/toast' @@ -205,6 +206,13 @@ desc: 'Handle errors in flows after all retry attempts have been exhausted.', documentationLink: 'https://www.windmill.dev/docs/flows/flow_error_handler', Icon: Bug + }, + { + value: 'preprocessor', + title: 'Preprocessor', + desc: 'Transform incoming requests before they are passed to the flow.', + documentationLink: 'https://www.windmill.dev/docs/core_concepts/preprocessors', + Icon: Shuffle } ] diff --git a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte index 779a9a9e70..4e94cc449f 100644 --- a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte +++ b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte @@ -96,8 +96,7 @@ on:applyArgs on:addPreprocessor={async () => { await insertNewPreprocessorModule(flowStore, flowStateStore, { - language: 'bun', - subkind: 'preprocessor' + language: 'bun' }) $selectedId = 'preprocessor' }} diff --git a/frontend/src/lib/components/flows/content/ScriptEditorDrawer.svelte b/frontend/src/lib/components/flows/content/ScriptEditorDrawer.svelte index d7656e5aca..b696e0600b 100644 --- a/frontend/src/lib/components/flows/content/ScriptEditorDrawer.svelte +++ b/frontend/src/lib/components/flows/content/ScriptEditorDrawer.svelte @@ -43,7 +43,7 @@ content: string schema?: any tag?: string - kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | undefined + kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | 'preprocessor' | undefined envs?: string[] ws_error_handler_muted?: boolean dedicated_worker?: boolean @@ -64,7 +64,7 @@ content: string schema?: any tag?: string - kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | undefined + kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | 'preprocessor' | undefined envs?: string[] ws_error_handler_muted?: boolean dedicated_worker?: boolean diff --git a/frontend/src/lib/components/flows/flowStateUtils.ts b/frontend/src/lib/components/flows/flowStateUtils.ts index fe4d724cbe..32216d306d 100644 --- a/frontend/src/lib/components/flows/flowStateUtils.ts +++ b/frontend/src/lib/components/flows/flowStateUtils.ts @@ -75,7 +75,7 @@ export async function pickFlow( export async function createInlineScriptModule( language: RawScript['language'], kind: Script['kind'], - subkind: 'pgsql' | 'flow' | 'preprocessor', + subkind: 'pgsql' | 'flow' | undefined, id: string, summary?: string ): Promise<[FlowModule, FlowModuleState]> { @@ -300,7 +300,6 @@ export async function insertNewPreprocessorModule( flowStateStore: Writable, inlineScript?: { language: RawScript['language'] - subkind: 'preprocessor' }, wsScript?: { path: string; summary: string; hash: string | undefined } ) { @@ -313,8 +312,8 @@ export async function insertNewPreprocessorModule( if (inlineScript) { ;[module, state] = await createInlineScriptModule( inlineScript.language, - 'script', - inlineScript.subkind, + 'preprocessor', + undefined, 'preprocessor' ) } else if (wsScript) { diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index fdb68b5610..f3f840825b 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -893,7 +893,6 @@ export function initialCode( | 'docker' | 'powershell' | 'bunnative' - | 'preprocessor' | undefined ): string { if (!kind) { @@ -911,8 +910,6 @@ export function initialCode( return INITIAL_CODE.mysql.script } else if (subkind === 'fetch') { return INITIAL_CODE.deno.fetch - } else if (subkind === 'preprocessor') { - return INITIAL_CODE.deno.preprocessor } else { return INITIAL_CODE.deno.script } @@ -920,6 +917,8 @@ export function initialCode( return INITIAL_CODE.deno.failure } else if (kind === 'approval') { return INITIAL_CODE.deno.approval + } else if (kind === 'preprocessor') { + return INITIAL_CODE.deno.preprocessor } else { return INITIAL_CODE.deno.script } @@ -930,10 +929,10 @@ export function initialCode( return INITIAL_CODE.python3.approval } else if (kind === 'failure') { return INITIAL_CODE.python3.failure + } else if (kind === 'preprocessor') { + return INITIAL_CODE.python3.preprocessor } else if (subkind === 'flow') { return INITIAL_CODE.python3.clear - } else if (subkind === 'preprocessor') { - return INITIAL_CODE.python3.preprocessor } else { return INITIAL_CODE.python3.script } @@ -978,7 +977,7 @@ export function initialCode( return INITIAL_CODE.bun.approval } else if (kind === 'failure') { return INITIAL_CODE.bun.failure - } else if (subkind === 'preprocessor') { + } else if (kind === 'preprocessor') { return INITIAL_CODE.bun.preprocessor } else if (subkind === 'flow') { return INITIAL_CODE.bun.clear