diff --git a/.github/workflows/docker-image-rpi4.yml b/.github/workflows/docker-image-rpi4.yml index bb270aac8a..1042833c16 100644 --- a/.github/workflows/docker-image-rpi4.yml +++ b/.github/workflows/docker-image-rpi4.yml @@ -67,7 +67,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=embedding,parquet,openidconnect,license,http_trigger,zip,oauth2,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages,deno_core,mcp + features=embedding,parquet,openidconnect,license,http_trigger,zip,oauth2,postgres_trigger,mqtt_trigger,websocket,smtp,native_trigger,static_frontend,all_languages,deno_core,mcp tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dev ${{ steps.meta-public.outputs.tags }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 6d28ad4953..23e1a69c64 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -97,7 +97,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages,deno_core,mcp,bedrock,private + features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,native_trigger,static_frontend,agent_worker_server,all_languages,deno_core,mcp,bedrock,private tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }} ${{ steps.meta-public.outputs.tags }} diff --git a/backend/.sqlx/query-8701ec4c8a9cd5ec71093483516c864f6b5b26f644d75a35fa732346b013e270.json b/backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json similarity index 72% rename from backend/.sqlx/query-8701ec4c8a9cd5ec71093483516c864f6b5b26f644d75a35fa732346b013e270.json rename to backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json index b742309096..f80b75b5ec 100644 --- a/backend/.sqlx/query-8701ec4c8a9cd5ec71093483516c864f6b5b26f644d75a35fa732346b013e270.json +++ b/backend/.sqlx/query-ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n nt.external_id,\n nt.workspace_id,\n nt.service_name AS \"service_name!: ServiceName\",\n nt.script_path,\n nt.is_flow,\n nt.webhook_token_prefix,\n nt.service_config,\n nt.error,\n nt.created_at,\n nt.updated_at\n FROM\n native_trigger nt\n WHERE\n nt.workspace_id = $1 AND\n nt.service_name = $2 AND\n (\n (nt.is_flow = false AND EXISTS (\n SELECT 1 FROM script s\n WHERE s.workspace_id = nt.workspace_id\n AND s.path = nt.script_path\n ))\n OR\n (nt.is_flow = true AND EXISTS (\n SELECT 1 FROM flow f\n WHERE f.workspace_id = nt.workspace_id\n AND f.path = nt.script_path\n ))\n )\n LIMIT $3\n OFFSET $4\n ", + "query": "\n SELECT\n nt.external_id,\n nt.workspace_id,\n nt.service_name AS \"service_name!: ServiceName\",\n nt.script_path,\n nt.is_flow,\n nt.webhook_token_prefix,\n nt.service_config,\n nt.error,\n nt.created_at,\n nt.updated_at\n FROM\n native_trigger nt\n WHERE\n nt.workspace_id = $1 AND\n nt.service_name = $2 AND\n ($5::text IS NULL OR nt.script_path = $5) AND\n ($6::bool IS NULL OR nt.is_flow = $6) AND\n (\n (nt.is_flow = false AND EXISTS (\n SELECT 1 FROM script s\n WHERE s.workspace_id = nt.workspace_id\n AND s.path = nt.script_path\n ))\n OR\n (nt.is_flow = true AND EXISTS (\n SELECT 1 FROM flow f\n WHERE f.workspace_id = nt.workspace_id\n AND f.path = nt.script_path\n ))\n )\n LIMIT $3\n OFFSET $4\n ", "describe": { "columns": [ { @@ -77,7 +77,9 @@ } }, "Int8", - "Int8" + "Int8", + "Text", + "Bool" ] }, "nullable": [ @@ -93,5 +95,5 @@ false ] }, - "hash": "8701ec4c8a9cd5ec71093483516c864f6b5b26f644d75a35fa732346b013e270" + "hash": "ecab1af12a7afa685c056b9d0e526275203fc8ecddf83ca6d05c9fb77e46e7ee" } diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 51a0217ec9..1824f3018e 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -12247,6 +12247,16 @@ paths: $ref: "#/components/schemas/NativeServiceName" - $ref: "#/components/parameters/Page" - $ref: "#/components/parameters/PerPage" + - name: path + description: filter by script path + in: query + schema: + type: string + - name: is_flow + description: filter by is_flow + in: query + schema: + type: boolean responses: "200": description: native triggers list diff --git a/backend/windmill-api/src/native_triggers/handler.rs b/backend/windmill-api/src/native_triggers/handler.rs index 930739e244..3c42b5261b 100644 --- a/backend/windmill-api/src/native_triggers/handler.rs +++ b/backend/windmill-api/src/native_triggers/handler.rs @@ -43,6 +43,8 @@ async fn require_is_writer_on_runnable( pub struct ListQuery { pub page: Option, pub per_page: Option, + pub path: Option, + pub is_flow: Option, } #[derive(Debug, Serialize)] @@ -502,6 +504,8 @@ async fn list_native_triggers_handler( service_name, query.page, query.per_page, + query.path.as_deref(), + query.is_flow, ) .await?; tx.commit().await?; diff --git a/backend/windmill-api/src/native_triggers/mod.rs b/backend/windmill-api/src/native_triggers/mod.rs index 029fe9f488..8c0b829478 100644 --- a/backend/windmill-api/src/native_triggers/mod.rs +++ b/backend/windmill-api/src/native_triggers/mod.rs @@ -820,6 +820,8 @@ pub async fn list_native_triggers<'c, E: sqlx::Executor<'c, Database = Postgres> service_name: ServiceName, page: Option, per_page: Option, + path: Option<&str>, + is_flow: Option, ) -> Result> { let offset = (page.unwrap_or(0) * per_page.unwrap_or(100)) as i64; let limit = per_page.unwrap_or(100) as i64; @@ -843,6 +845,8 @@ pub async fn list_native_triggers<'c, E: sqlx::Executor<'c, Database = Postgres> WHERE nt.workspace_id = $1 AND nt.service_name = $2 AND + ($5::text IS NULL OR nt.script_path = $5) AND + ($6::bool IS NULL OR nt.is_flow = $6) AND ( (nt.is_flow = false AND EXISTS ( SELECT 1 FROM script s @@ -862,7 +866,9 @@ pub async fn list_native_triggers<'c, E: sqlx::Executor<'c, Database = Postgres> workspace_id, service_name as ServiceName, limit, - offset + offset, + path, + is_flow ) .fetch_all(db) .await?; diff --git a/backend/windmill-api/src/native_triggers/sync.rs b/backend/windmill-api/src/native_triggers/sync.rs index da3feb7f33..ca955630aa 100644 --- a/backend/windmill-api/src/native_triggers/sync.rs +++ b/backend/windmill-api/src/native_triggers/sync.rs @@ -194,7 +194,7 @@ pub async fn sync_workspace_triggers( ); let windmill_triggers = - list_native_triggers(db, workspace_id, T::SERVICE_NAME, None, None).await?; + list_native_triggers(db, workspace_id, T::SERVICE_NAME, None, None, None, None).await?; if windmill_triggers.is_empty() { tracing::info!( diff --git a/backend/windmill-api/src/triggers/email/handler_oss.rs b/backend/windmill-api/src/triggers/email/handler_oss.rs index 03a377df98..9a688c2cf1 100644 --- a/backend/windmill-api/src/triggers/email/handler_oss.rs +++ b/backend/windmill-api/src/triggers/email/handler_oss.rs @@ -32,7 +32,7 @@ impl TriggerCrud for EmailTrigger { const SUPPORTS_TEST_CONNECTION: bool = false; const ROUTE_PREFIX: &'static str = "/email_triggers"; const DEPLOYMENT_NAME: &'static str = ""; - const IS_CLOUD_HOSTED: bool = false; + const IS_ALLOWED_ON_CLOUD: bool = false; fn get_deployed_object(path: String) -> DeployedObject { DeployedObject::EmailTrigger { path } diff --git a/backend/windmill-api/src/triggers/handler.rs b/backend/windmill-api/src/triggers/handler.rs index 85df62f82e..d0d7e596dd 100644 --- a/backend/windmill-api/src/triggers/handler.rs +++ b/backend/windmill-api/src/triggers/handler.rs @@ -762,7 +762,7 @@ pub fn generate_trigger_routers() -> Router { ); } - #[cfg(all(feature = "enterprise", feature = "smtp", feature = "private"))] + #[cfg(all(feature = "smtp", feature = "private"))] { use crate::triggers::email::EmailTrigger; diff --git a/backend/windmill-api/src/triggers/mod.rs b/backend/windmill-api/src/triggers/mod.rs index 20fec351bb..b73f27ed33 100644 --- a/backend/windmill-api/src/triggers/mod.rs +++ b/backend/windmill-api/src/triggers/mod.rs @@ -11,7 +11,7 @@ pub enum HandlerAction { // Future variants can be added here (e.g., Script, Flow, etc.) } -#[cfg(all(feature = "smtp", feature = "enterprise", feature = "private"))] +#[cfg(all(feature = "smtp", feature = "private"))] pub mod email; #[cfg(all(feature = "gcp_trigger", feature = "enterprise", feature = "private"))] pub mod gcp; diff --git a/backend/windmill-api/src/workspaces_export.rs b/backend/windmill-api/src/workspaces_export.rs index 8f14d81ac1..2631e22624 100644 --- a/backend/windmill-api/src/workspaces_export.rs +++ b/backend/windmill-api/src/workspaces_export.rs @@ -810,7 +810,7 @@ pub(crate) async fn tarball_workspace( for service_name in ServiceName::iter() { let native_triggers = - list_native_triggers(&mut *tx, &w_id, service_name, None, None).await?; + list_native_triggers(&mut *tx, &w_id, service_name, None, None, None, None).await?; for trigger in native_triggers { let trigger_str = &to_string_without_metadata( diff --git a/frontend/src/lib/components/triggers/triggers.svelte.ts b/frontend/src/lib/components/triggers/triggers.svelte.ts index 4f7fc508a1..3e56efff33 100644 --- a/frontend/src/lib/components/triggers/triggers.svelte.ts +++ b/frontend/src/lib/components/triggers/triggers.svelte.ts @@ -473,16 +473,14 @@ export class Triggers { ): Promise { if (!workspaceId) return try { - const allTriggers: NativeTrigger[] = await NativeTriggerService.listNativeTriggers({ + const triggers: NativeTrigger[] = await NativeTriggerService.listNativeTriggers({ workspace: workspaceId, - serviceName + serviceName, + path, + isFlow }) - // Filter triggers for this specific script/flow path - const filteredTriggers = allTriggers.filter( - (t) => t.script_path === path && t.is_flow === isFlow - ) // Convert to the trigger format used by updateTriggers - const triggerData = filteredTriggers.map((t) => ({ + const triggerData = triggers.map((t) => ({ path: t.external_id, script_path: t.script_path, is_flow: t.is_flow, @@ -511,15 +509,15 @@ export class Triggers { this.fetchHttpTriggers(triggersCountStore, workspaceId, path, isFlow, user), this.fetchWebsocketTriggers(triggersCountStore, workspaceId, path, isFlow, user), this.fetchPostgresTriggers(triggersCountStore, workspaceId, path, isFlow, user), - this.fetchNatsTriggers(triggersCountStore, workspaceId, path, isFlow, user), this.fetchMqttTriggers(triggersCountStore, workspaceId, path, isFlow, user), - this.fetchEmailTriggers(triggersCountStore, workspaceId, path, isFlow, user), this.fetchNativeTriggers('nextcloud', workspaceId, path, isFlow, user), ...(get(enterpriseLicense) ? [ this.fetchKafkaTriggers(triggersCountStore, workspaceId, path, isFlow, user), this.fetchSqsTriggers(triggersCountStore, workspaceId, path, isFlow, user), - this.fetchGcpTriggers(triggersCountStore, workspaceId, path, isFlow, user) + this.fetchGcpTriggers(triggersCountStore, workspaceId, path, isFlow, user), + this.fetchEmailTriggers(triggersCountStore, workspaceId, path, isFlow, user), + this.fetchNatsTriggers(triggersCountStore, workspaceId, path, isFlow, user) ] : []) ])