From 63397754046eed41d32e28d4698db37b4c9b9710 Mon Sep 17 00:00:00 2001 From: dieriba Date: Thu, 10 Apr 2025 22:39:01 +0200 Subject: [PATCH] feat: add gcp trigger (#5501) * update: add migration for gcp_trigger table, add cli method gcp and add gcp_trigger args for github ci * update: add gcp module and routing it in lib.rs * update: added gcp type to TRIGGER KIND type in db, add new feature condition to try_get_fn and added gcp_trigger feature in cargo file * update: add ui for gcp trigger, added missing triggers type for job kin, add gcp trigger in deploy to functionallity * adding google cloud crate * update: handle pull and push delivery * update: handle pull and push delivery * update: handle push event, changed front ui * update: ui * fix: capture for gcp * update: automatically manage pub sub subscription and refactoring * capture done * update cli types * fix: wrong func argument and type openapi * fix: missing import * update .sqlx * update: svg color and remove pulse button for capture push gcp * update: handle deployto * update script helper and link to hub gcp script/flow * update gcp representation * update: add confirmation modal * add unique index to mitigate same subscriber id, fix `zombie worker`, update test connection logic * Update frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Update cli/gen/services.gen.ts Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * nits * update repo ref * fix feature function * update dependencies * update .sqlx * fix missing import * update: handle existing subscription and creating new one or update it * fix ee build * handle existing config properly * update .sqlx * update .sqlx * remove unused * update documentation link fix ci * use on instance of empty_string_as_none fn * update refo ref * updat script_helper * update ui * update migration * add missing arguments * fix and nits * update repo ref * remove unused * nits * add doc links * nits * Update frontend/src/lib/components/triggers/gcp/GcpTriggerPanel.svelte Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Update frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * use trigger path as default route path * update .sqlx * update repo ref * update ref * update route path * update types * fix deploy to * nits * update repo ref * update .sqlx * Update frontend/src/lib/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * nits * nits * nits * remove dupliacte fn and update repo ref * remove unused import * fix missing import * fix: wong name var * update script helper and template script * Update frontend/src/lib/script_helpers.ts Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Update ee-repo-ref.txt --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: HugoCasa --- .github/workflows/build-publish-rh-image.yml | 4 +- .github/workflows/build_windows_worker_.yml | 2 +- .github/workflows/docker-image.yml | 4 +- .github/workflows/publish_windows_worker.yml | 2 +- ...35bb81146a4cfae0ec408435570e0813a3bef.json | 128 +++++ ...60f5c3561c37e9c6f2834d234a862a475a6eb.json | 26 + ...5f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json | 126 +++++ ...518b42f4cdb33e034441015494bd26c172d2.json} | 10 +- ...5199960264b54c1ddf928c0c654ab15176f63.json | 25 + ...2cf0e4086030f3b7994e4892392765cbe1517.json | 23 + ...4f4683a12b82b972842f88f5c01111580224d.json | 17 + ...31617043fcc0bea3ef62c50fcd881f3d48605.json | 35 ++ ...bd0de7e03c539ee046955543d9693551246f7.json | 14 - ...ad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json} | 7 +- ...a2524943ba277c5f9a37c06bd5ee14fd46bda.json | 17 + ...b3d956c004376102ccc1707fc016801599dbd.json | 36 ++ ...a6c391c4d0054a618b861464ee37239f1f1e0.json | 4 +- ...8b82359c182ee2a5da6df35a4375d5d2d1ef7.json | 65 +++ ...7998ea800860ede856e5fc6cd1f57d5408333.json | 16 + ...ea5d698ac09d8264e35dfaa4cd8edc9e8414.json} | 7 +- ...a15fbba193262f7895c2bba90feb4215d6f3.json} | 10 +- ...4044f505f49edcd2ebeee4a77eae737f48795.json | 14 + ...39319a854f761a300970e2fd909f8058ec566.json | 17 - ...22e4276c1da653475628889ce17dc904fbaa.json} | 7 +- ...06bf08c28efe82b68b3d44bafbd3d0e91c29.json} | 7 +- ...329f748006ab131489d2fcac21d32641bb633.json | 24 + ...4e44ef5a0f082bdde854900064325adc4dd77.json | 15 - ...d59f418ed6fc2a98ddb9bbc33dce5f029d904.json | 15 + ...ab0dc7217d1b3f86f362c213982984d2cf652.json | 26 + ...895329d2daf722d360fbcbdef6f04bb1400f.json} | 10 +- ...e637e9e156cd85b69126c87dfff89a47711d.json} | 7 +- ...f81572818177a6024e743b12f558b46edf74c.json | 50 ++ ...f14572ac204cfe377166aa1d91cf58f731f50.json | 15 + ...4d91ba89aab2318d85621ad2868017adfb48a.json | 17 + ...05d394a7cbcf0038c72a78add5c7b02ef5927.json | 2 +- ...0912d0221d191b8ab091601cb53cdd932ad58.json | 25 + ...e08f4c248e1af1c6580bdf8f2735ae1388981.json | 15 + ...6874ee8b277a2914dff6f9c33a1f5a2351114.json | 17 - ...2f7a4d3bbe673f7c48153819dab385a5cb357.json | 129 +++++ ...886ea136f2327169bf93f126e2ef130d0946.json} | 7 +- ...2ab7e0bf26431158fbfb5f0023ed847ca7dc5.json | 16 + backend/.vscode/settings.json | 2 +- backend/Cargo.lock | 143 ++++- backend/Cargo.toml | 5 +- backend/ee-repo-ref.txt | 2 +- ...50323135044_add-gcp-trigger-table.down.sql | 3 + ...0250323135044_add-gcp-trigger-table.up.sql | 80 +++ ...ger-kind-to-job-trigger-kind-type.down.sql | 1 + ...igger-kind-to-job-trigger-kind-type.up.sql | 3 + backend/src/monitor.rs | 13 +- backend/windmill-api/Cargo.toml | 6 +- backend/windmill-api/openapi.yaml | 439 ++++++++++++++- backend/windmill-api/src/auth.rs | 1 - backend/windmill-api/src/capture.rs | 463 +++++++++++---- backend/windmill-api/src/gcp_triggers_ee.rs | 133 +++++ backend/windmill-api/src/http_trigger_auth.rs | 8 +- backend/windmill-api/src/http_triggers.rs | 2 +- backend/windmill-api/src/lib.rs | 36 ++ backend/windmill-api/src/resources.rs | 12 +- backend/windmill-api/src/workspaces.rs | 4 +- backend/windmill-api/src/workspaces_export.rs | 41 ++ backend/windmill-common/src/error.rs | 6 + backend/windmill-common/src/utils.rs | 20 +- backend/windmill-queue/src/jobs.rs | 3 + backend/windmill-worker/src/common.rs | 1 + backend/windmill-worker/src/mssql_executor.rs | 16 +- cli/gen/core/OpenAPI.ts | 2 +- cli/gen/services.gen.ts | 223 +++++++- cli/gen/types.gen.ts | 233 +++++++- cli/sync.ts | 13 +- cli/trigger.ts | 12 +- cli/types.ts | 4 + .../src/lib/components/DeployWorkspace.svelte | 3 +- frontend/src/lib/components/Path.svelte | 10 +- frontend/src/lib/components/ShareModal.svelte | 1 + .../details/DetailPageDetailPanel.svelte | 2 + .../details/DetailPageLayout.svelte | 3 + .../details/DetailPageTriggerPanel.svelte | 14 +- .../renderers/triggers/TriggersBadge.svelte | 8 +- .../components/icons/GoogleCloudIcon.svelte | 48 +- .../components/sidebar/OperatorMenu.svelte | 5 + .../components/sidebar/SidebarContent.svelte | 10 +- frontend/src/lib/components/triggers.ts | 3 + .../components/triggers/CaptureButton.svelte | 7 + .../components/triggers/CaptureSection.svelte | 7 +- .../components/triggers/CaptureTable.svelte | 4 +- .../components/triggers/CaptureWrapper.svelte | 55 +- .../triggers/TestTriggerConnection.svelte | 13 +- .../components/triggers/TriggersEditor.svelte | 26 +- .../triggers/TriggersEditorSection.svelte | 21 +- .../triggers/TriggersWrapper.svelte | 16 + .../triggers/gcp/GcpTriggerEditor.svelte | 27 + .../gcp/GcpTriggerEditorConfigSection.svelte | 342 +++++++++++ .../triggers/gcp/GcpTriggerEditorInner.svelte | 293 ++++++++++ .../triggers/gcp/GcpTriggerPanel.svelte | 131 +++++ .../http/RouteBodyTransformerOption.svelte | 7 +- .../http/RouteEditorConfigSection.svelte | 6 +- .../src/lib/components/triggers/http/utils.ts | 5 +- frontend/src/lib/script_helpers.ts | 40 +- frontend/src/lib/utils_deployable.ts | 75 ++- .../src/routes/(root)/(logged)/+layout.svelte | 6 +- .../(logged)/flows/get/[...path]/+page.svelte | 7 + .../(root)/(logged)/gcp_triggers/+page.js | 5 + .../(root)/(logged)/gcp_triggers/+page.svelte | 530 ++++++++++++++++++ .../(root)/(logged)/routes/+page.svelte | 4 +- .../scripts/get/[...hash]/+page.svelte | 6 + 106 files changed, 4351 insertions(+), 332 deletions(-) create mode 100644 backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json create mode 100644 backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json create mode 100644 backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json rename backend/.sqlx/{query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json => query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json} (53%) create mode 100644 backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json create mode 100644 backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json create mode 100644 backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json create mode 100644 backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json delete mode 100644 backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json rename backend/.sqlx/{query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json => query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json} (59%) create mode 100644 backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json create mode 100644 backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json create mode 100644 backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json create mode 100644 backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json rename backend/.sqlx/{query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json => query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json} (70%) rename backend/.sqlx/{query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json => query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json} (64%) create mode 100644 backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json delete mode 100644 backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json rename backend/.sqlx/{query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json => query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json} (68%) rename backend/.sqlx/{query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json => query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json} (63%) create mode 100644 backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json delete mode 100644 backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json create mode 100644 backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json create mode 100644 backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json rename backend/.sqlx/{query-9ae20f2f29406cfa5337736ad710c496f1757d950cdec63c93c77fe79d5212cc.json => query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json} (82%) rename backend/.sqlx/{query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json => query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json} (51%) create mode 100644 backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json create mode 100644 backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json create mode 100644 backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json create mode 100644 backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json create mode 100644 backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json delete mode 100644 backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json create mode 100644 backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json rename backend/.sqlx/{query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json => query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json} (64%) create mode 100644 backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json create mode 100644 backend/migrations/20250323135044_add-gcp-trigger-table.down.sql create mode 100644 backend/migrations/20250323135044_add-gcp-trigger-table.up.sql create mode 100644 backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql create mode 100644 backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql create mode 100644 backend/windmill-api/src/gcp_triggers_ee.rs create mode 100644 frontend/src/lib/components/triggers/gcp/GcpTriggerEditor.svelte create mode 100644 frontend/src/lib/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte create mode 100644 frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte create mode 100644 frontend/src/lib/components/triggers/gcp/GcpTriggerPanel.svelte create mode 100644 frontend/src/routes/(root)/(logged)/gcp_triggers/+page.js create mode 100644 frontend/src/routes/(root)/(logged)/gcp_triggers/+page.svelte diff --git a/.github/workflows/build-publish-rh-image.yml b/.github/workflows/build-publish-rh-image.yml index b509064f29..10d2fe43d9 100644 --- a/.github/workflows/build-publish-rh-image.yml +++ b/.github/workflows/build-publish-rh-image.yml @@ -64,7 +64,7 @@ jobs: platforms: linux/amd64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages secrets: | rh_username=${{ secrets.RH_USERNAME }} rh_password=${{ secrets.RH_PASSWORD }} @@ -81,7 +81,7 @@ jobs: platforms: linux/arm64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages secrets: | rh_username=${{ secrets.RH_USERNAME }} rh_password=${{ secrets.RH_PASSWORD }} diff --git a/.github/workflows/build_windows_worker_.yml b/.github/workflows/build_windows_worker_.yml index d861034187..785ade3201 100644 --- a/.github/workflows/build_windows_worker_.yml +++ b/.github/workflows/build_windows_worker_.yml @@ -51,7 +51,7 @@ jobs: $env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static" mkdir frontend/build && cd backend New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force - cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages + cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages - name: Rename binary with corresponding architecture run: | Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe" diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 06aebf1052..23d59ff604 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -95,7 +95,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 + features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }} ${{ steps.meta-public.outputs.tags }} @@ -157,7 +157,7 @@ jobs: platforms: linux/amd64,linux/arm64 push: true build-args: | - features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages + features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }} ${{ steps.meta-ee-public.outputs.tags }} diff --git a/.github/workflows/publish_windows_worker.yml b/.github/workflows/publish_windows_worker.yml index 20a30e936f..5b591abc3c 100644 --- a/.github/workflows/publish_windows_worker.yml +++ b/.github/workflows/publish_windows_worker.yml @@ -53,7 +53,7 @@ jobs: $env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static" mkdir frontend/build && cd backend New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force - cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages + cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages - name: Rename binary with corresponding architecture run: | Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe" diff --git a/backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json b/backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json new file mode 100644 index 0000000000..06390d0ce9 --- /dev/null +++ b/backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json @@ -0,0 +1,128 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n gcp_trigger\n WHERE \n workspace_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "subscription_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "topic_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "delivery_type: _", + "type_info": { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + } + }, + { + "ordinal": 5, + "name": "delivery_config: _", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 12, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 14, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 15, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false + ] + }, + "hash": "0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef" +} diff --git a/backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json b/backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json new file mode 100644 index 0000000000..280db517dd --- /dev/null +++ b/backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n enabled = $1, \n email = $2, \n edited_by = $3, \n edited_at = now(), \n server_id = NULL, \n error = NULL\n WHERE \n path = $4 AND \n workspace_id = $5 \n RETURNING 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Bool", + "Varchar", + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb" +} diff --git a/backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json b/backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json new file mode 100644 index 0000000000..5f76c31d8b --- /dev/null +++ b/backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json @@ -0,0 +1,126 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM\n gcp_trigger\n WHERE\n delivery_type != 'push'::DELIVERY_MODE AND\n enabled IS TRUE\n AND (last_server_ping IS NULL OR\n last_server_ping < now() - interval '15 seconds'\n )\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "subscription_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "topic_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "delivery_type: _", + "type_info": { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + } + }, + { + "ordinal": 5, + "name": "delivery_config: _", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 12, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 14, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 15, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false + ] + }, + "hash": "15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18" +} diff --git a/backend/.sqlx/query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json b/backend/.sqlx/query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json similarity index 53% rename from backend/.sqlx/query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json rename to backend/.sqlx/query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json index 7b30e079f0..5b810738b3 100644 --- a/backend/.sqlx/query-e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039.json +++ b/backend/.sqlx/query-23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT trigger_config as \"trigger_config: _\", owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'", + "query": "\n SELECT \n trigger_config AS \"trigger_config: _\", \n owner, \n email\n FROM \n capture_config\n WHERE \n workspace_id = $1\n AND path = $2\n AND is_flow = $3\n AND trigger_kind = $4\n AND last_client_ping > NOW() - INTERVAL '10 seconds'\n AND (\n $5::bool IS FALSE\n OR (\n trigger_config IS NOT NULL\n AND trigger_config ->> 'delivery_type' = 'push'\n )\n )\n ", "describe": { "columns": [ { @@ -37,11 +37,13 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } - } + }, + "Bool" ] }, "nullable": [ @@ -50,5 +52,5 @@ false ] }, - "hash": "e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039" + "hash": "23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2" } diff --git a/backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json b/backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json new file mode 100644 index 0000000000..d64d8f404b --- /dev/null +++ b/backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config \n SET \n server_id = $1,\n last_server_ping = now(), \n error = 'Connecting...' \n WHERE \n last_client_ping > NOW() - INTERVAL '10 seconds' AND \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp' AND \n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') \n RETURNING true\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [ + null + ] + }, + "hash": "299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63" +} diff --git a/backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json b/backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json new file mode 100644 index 0000000000..9b7581526e --- /dev/null +++ b/backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT EXISTS(\n SELECT \n 1 \n FROM \n gcp_trigger \n WHERE \n path = $1 AND \n workspace_id = $2\n )", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517" +} diff --git a/backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json b/backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json new file mode 100644 index 0000000000..5ab1ed1bc3 --- /dev/null +++ b/backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture\n SET \n path = $1\n WHERE \n path = $2 \n AND workspace_id = $3 \n AND is_flow = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d" +} diff --git a/backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json b/backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json new file mode 100644 index 0000000000..b225a5a1da --- /dev/null +++ b/backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO gcp_trigger (\n gcp_resource_path,\n subscription_id,\n topic_id,\n delivery_type,\n delivery_config,\n workspace_id, \n path, \n script_path, \n is_flow, \n email, \n enabled, \n edited_by\n ) \n VALUES (\n $1, \n $2, \n $3, \n $4,\n $5,\n $6, \n $7, \n $8, \n $9,\n $10,\n $11,\n $12\n )", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + }, + "Jsonb", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Varchar", + "Bool", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605" +} diff --git a/backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json b/backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json deleted file mode 100644 index 0df0167c42..0000000000 --- a/backend/.sqlx/query-41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "DELETE FROM capture WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7" -} diff --git a/backend/.sqlx/query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json b/backend/.sqlx/query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json similarity index 59% rename from backend/.sqlx/query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json rename to backend/.sqlx/query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json index 8c2a88d485..c1a38be77e 100644 --- a/backend/.sqlx/query-c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534.json +++ b/backend/.sqlx/query-42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4", + "query": "\n UPDATE \n capture_config\n SET \n last_client_ping = NOW()\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND trigger_kind = $4\n ", "describe": { "columns": [], "parameters": { @@ -21,7 +21,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -30,5 +31,5 @@ }, "nullable": [] }, - "hash": "c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534" + "hash": "42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2" } diff --git a/backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json b/backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json new file mode 100644 index 0000000000..7d6ecdbf32 --- /dev/null +++ b/backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config \n SET \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp'\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda" +} diff --git a/backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json b/backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json new file mode 100644 index 0000000000..87d384f5a1 --- /dev/null +++ b/backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json @@ -0,0 +1,36 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n gcp_resource_path = $1,\n subscription_id = $2,\n topic_id = $3,\n delivery_type = $4,\n delivery_config = $5,\n is_flow = $6, \n edited_by = $7, \n email = $8,\n script_path = $9,\n path = $10,\n enabled = $11,\n edited_at = now(), \n error = NULL,\n server_id = NULL\n WHERE \n workspace_id = $12 AND \n path = $13\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Varchar", + { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + }, + "Jsonb", + "Bool", + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Bool", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd" +} diff --git a/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json b/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json index 5d0677ae7e..d8a93c797d 100644 --- a/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json +++ b/backend/.sqlx/query-4aaab98ebdaa90f1edf49ac96fba6c391c4d0054a618b861464ee37239f1f1e0.json @@ -220,7 +220,9 @@ "schedule", "app", "ui", - "postgres" + "postgres", + "sqs", + "gcp" ] } } diff --git a/backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json b/backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json new file mode 100644 index 0000000000..f010362e6f --- /dev/null +++ b/backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json @@ -0,0 +1,65 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT \n gcp_resource_path, \n script_path,\n is_flow, \n workspace_id,\n path,\n edited_by,\n email,\n delivery_config AS \"delivery_config: _\"\n FROM\n gcp_trigger\n WHERE\n workspace_id = $1 AND\n path = $2 AND\n delivery_type = 'push'::DELIVERY_MODE \n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "delivery_config: _", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true + ] + }, + "hash": "5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7" +} diff --git a/backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json b/backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json new file mode 100644 index 0000000000..8b9a46c4d0 --- /dev/null +++ b/backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE \n capture_config \n SET \n last_server_ping = NULL \n WHERE \n workspace_id = $1 AND \n path = $2 AND \n is_flow = $3 AND \n trigger_kind = 'gcp' AND \n server_id IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333" +} diff --git a/backend/.sqlx/query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json b/backend/.sqlx/query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json similarity index 70% rename from backend/.sqlx/query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json rename to backend/.sqlx/query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json index 60332810b2..2e4638f1f7 100644 --- a/backend/.sqlx/query-e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7.json +++ b/backend/.sqlx/query-6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", payload as \"payload!: _\", trigger_extra as \"trigger_extra: _\" FROM capture WHERE id = $1 AND workspace_id = $2", + "query": "\n SELECT \n id, \n created_at, \n trigger_kind AS \"trigger_kind: _\", \n payload AS \"payload!: _\", \n trigger_extra AS \"trigger_extra: _\"\n FROM \n capture\n WHERE \n id = $1 \n AND workspace_id = $2\n ", "describe": { "columns": [ { @@ -29,7 +29,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -60,5 +61,5 @@ true ] }, - "hash": "e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7" + "hash": "6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414" } diff --git a/backend/.sqlx/query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json b/backend/.sqlx/query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json similarity index 64% rename from backend/.sqlx/query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json rename to backend/.sqlx/query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json index 61c4d20b04..a313dd6076 100644 --- a/backend/.sqlx/query-5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd.json +++ b/backend/.sqlx/query-7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", CASE WHEN pg_column_size(payload) < 40000 THEN payload ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as \"payload!: _\", trigger_extra as \"trigger_extra: _\"\n FROM capture\n WHERE workspace_id = $1\n AND path = $2 AND is_flow = $3\n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY created_at DESC\n OFFSET $5\n LIMIT $6", + "query": "\n SELECT \n id, \n created_at, \n trigger_kind AS \"trigger_kind: _\",\n CASE \n WHEN pg_column_size(payload) < 40000 THEN payload \n ELSE '\"WINDMILL_TOO_BIG\"'::jsonb \n END AS \"payload!: _\",\n trigger_extra AS \"trigger_extra: _\"\n FROM \n capture\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY \n created_at DESC\n OFFSET $5\n LIMIT $6\n ", "describe": { "columns": [ { @@ -29,7 +29,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -64,7 +65,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -81,5 +83,5 @@ true ] }, - "hash": "5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd" + "hash": "7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3" } diff --git a/backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json b/backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json new file mode 100644 index 0000000000..e1ab284262 --- /dev/null +++ b/backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM \n capture\n WHERE \n id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795" +} diff --git a/backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json b/backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json deleted file mode 100644 index 4e6d8e9ba2..0000000000 --- a/backend/.sqlx/query-7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Text", - "Text", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566" -} diff --git a/backend/.sqlx/query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json b/backend/.sqlx/query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json similarity index 68% rename from backend/.sqlx/query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json rename to backend/.sqlx/query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json index 45ce8d3f95..ca02b5c648 100644 --- a/backend/.sqlx/query-c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8.json +++ b/backend/.sqlx/query-7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT trigger_config as \"trigger_config: _\", trigger_kind as \"trigger_kind: _\", error, last_server_ping\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3", + "query": "\n SELECT \n trigger_config AS \"trigger_config: _\", \n trigger_kind AS \"trigger_kind: _\", \n error, \n last_server_ping\n FROM \n capture_config\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3\n ", "describe": { "columns": [ { @@ -24,7 +24,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -55,5 +56,5 @@ true ] }, - "hash": "c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8" + "hash": "7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa" } diff --git a/backend/.sqlx/query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json b/backend/.sqlx/query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json similarity index 63% rename from backend/.sqlx/query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json rename to backend/.sqlx/query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json index 643e0854bb..e2acac048f 100644 --- a/backend/.sqlx/query-71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447.json +++ b/backend/.sqlx/query-87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'", + "query": "\n SELECT \n owner, \n email\n FROM \n capture_config\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND trigger_kind = $4 \n AND last_client_ping > NOW() - INTERVAL '10 seconds'\n ", "describe": { "columns": [ { @@ -32,7 +32,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -44,5 +45,5 @@ false ] }, - "hash": "71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447" + "hash": "87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29" } diff --git a/backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json b/backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json new file mode 100644 index 0000000000..14d37809d5 --- /dev/null +++ b/backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n server_id = $1, \n last_server_ping = now(),\n error = 'Connecting...'\n WHERE \n enabled IS TRUE \n AND workspace_id = $2 \n AND path = $3 \n AND (last_server_ping IS NULL \n OR last_server_ping < now() - INTERVAL '15 seconds'\n ) \n RETURNING true\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633" +} diff --git a/backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json b/backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json deleted file mode 100644 index 2014d9e6e4..0000000000 --- a/backend/.sqlx/query-97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "DELETE FROM capture\n WHERE workspace_id = $1\n AND created_at <=\n (\n SELECT created_at\n FROM capture\n WHERE workspace_id = $1\n ORDER BY created_at DESC\n OFFSET $2\n LIMIT 1\n )", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77" -} diff --git a/backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json b/backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json new file mode 100644 index 0000000000..8748572af7 --- /dev/null +++ b/backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET\n last_server_ping = NULL \n WHERE \n workspace_id = $1 \n AND path = $2 \n AND server_id IS NULL", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904" +} diff --git a/backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json b/backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json new file mode 100644 index 0000000000..03b05af6fb --- /dev/null +++ b/backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config \n SET \n last_server_ping = now(), \n error = $1 \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp' AND \n server_id = $5 AND \n last_client_ping > NOW() - INTERVAL '10 seconds' \n RETURNING 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Bool", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652" +} diff --git a/backend/.sqlx/query-9ae20f2f29406cfa5337736ad710c496f1757d950cdec63c93c77fe79d5212cc.json b/backend/.sqlx/query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json similarity index 82% rename from backend/.sqlx/query-9ae20f2f29406cfa5337736ad710c496f1757d950cdec63c93c77fe79d5212cc.json rename to backend/.sqlx/query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json index 2b30281364..9526b72f55 100644 --- a/backend/.sqlx/query-9ae20f2f29406cfa5337736ad710c496f1757d950cdec63c93c77fe79d5212cc.json +++ b/backend/.sqlx/query-aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\"\n ", + "query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\",\n EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS \"gcp_used!\"\n ", "describe": { "columns": [ { @@ -37,6 +37,11 @@ "ordinal": 6, "name": "sqs_used!", "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "gcp_used!", + "type_info": "Bool" } ], "parameters": { @@ -51,8 +56,9 @@ null, null, null, + null, null ] }, - "hash": "9ae20f2f29406cfa5337736ad710c496f1757d950cdec63c93c77fe79d5212cc" + "hash": "aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f" } diff --git a/backend/.sqlx/query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json b/backend/.sqlx/query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json similarity index 51% rename from backend/.sqlx/query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json rename to backend/.sqlx/query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json index d2eab003f2..a20f4e47ad 100644 --- a/backend/.sqlx/query-62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a.json +++ b/backend/.sqlx/query-b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO capture_config\n (workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, error = NULL", + "query": "\n INSERT INTO capture_config (\n workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE \n SET \n trigger_config = $5, \n owner = $6, \n email = $7, \n server_id = NULL, \n error = NULL\n ", "describe": { "columns": [], "parameters": { @@ -21,7 +21,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -33,5 +34,5 @@ }, "nullable": [] }, - "hash": "62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a" + "hash": "b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d" } diff --git a/backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json b/backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json new file mode 100644 index 0000000000..e65e3cb60e --- /dev/null +++ b/backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json @@ -0,0 +1,50 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n path,\n is_flow,\n workspace_id,\n owner,\n email,\n trigger_config as \"trigger_config!: _\"\n FROM\n capture_config\n WHERE\n trigger_kind = 'gcp' AND\n last_client_ping > NOW() - INTERVAL '10 seconds' AND\n trigger_config IS NOT NULL AND\n trigger_config->>'delivery_type' IS DISTINCT FROM 'push' AND\n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 2, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "owner", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "trigger_config!: _", + "type_info": "Jsonb" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false, + true + ] + }, + "hash": "c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c" +} diff --git a/backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json b/backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json new file mode 100644 index 0000000000..65cc991931 --- /dev/null +++ b/backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE \n FROM \n gcp_trigger \n WHERE \n workspace_id = $1 AND \n path = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50" +} diff --git a/backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json b/backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json new file mode 100644 index 0000000000..5a67ebda84 --- /dev/null +++ b/backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n capture_config\n SET \n path = $1\n WHERE \n path = $2 \n AND workspace_id = $3 \n AND is_flow = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Text", + "Text", + "Bool" + ] + }, + "nullable": [] + }, + "hash": "c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a" +} diff --git a/backend/.sqlx/query-ddf2eccb78a310ed00c7d8b9c3f05d394a7cbcf0038c72a78add5c7b02ef5927.json b/backend/.sqlx/query-ddf2eccb78a310ed00c7d8b9c3f05d394a7cbcf0038c72a78add5c7b02ef5927.json index c2dfed73a2..5bfff47576 100644 --- a/backend/.sqlx/query-ddf2eccb78a310ed00c7d8b9c3f05d394a7cbcf0038c72a78add5c7b02ef5927.json +++ b/backend/.sqlx/query-ddf2eccb78a310ed00c7d8b9c3f05d394a7cbcf0038c72a78add5c7b02ef5927.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - null + true ] }, "hash": "ddf2eccb78a310ed00c7d8b9c3f05d394a7cbcf0038c72a78add5c7b02ef5927" diff --git a/backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json b/backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json new file mode 100644 index 0000000000..f98dd01404 --- /dev/null +++ b/backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger\n SET \n last_server_ping = now(),\n error = $1\n WHERE\n workspace_id = $2\n AND path = $3\n AND server_id = $4 \n AND enabled IS TRUE\n RETURNING 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "?column?", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58" +} diff --git a/backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json b/backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json new file mode 100644 index 0000000000..926e5c2474 --- /dev/null +++ b/backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM \n capture\n WHERE \n workspace_id = $1\n AND created_at <= (\n SELECT \n created_at\n FROM \n capture\n WHERE \n workspace_id = $1\n ORDER BY \n created_at DESC\n OFFSET $2\n LIMIT 1\n )\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981" +} diff --git a/backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json b/backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json deleted file mode 100644 index 461721c4c2..0000000000 --- a/backend/.sqlx/query-e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Text", - "Text", - "Bool" - ] - }, - "nullable": [] - }, - "hash": "e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114" -} diff --git a/backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json b/backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json new file mode 100644 index 0000000000..b20ae56e30 --- /dev/null +++ b/backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json @@ -0,0 +1,129 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n gcp_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "gcp_resource_path", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "subscription_id", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "topic_id", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "delivery_type: _", + "type_info": { + "Custom": { + "name": "delivery_mode", + "kind": { + "Enum": [ + "push", + "pull" + ] + } + } + } + }, + { + "ordinal": 5, + "name": "delivery_config: _", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "path", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "script_path", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "is_flow", + "type_info": "Bool" + }, + { + "ordinal": 9, + "name": "edited_by", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "edited_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 12, + "name": "server_id", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "last_server_ping", + "type_info": "Timestamptz" + }, + { + "ordinal": 14, + "name": "extra_perms", + "type_info": "Jsonb" + }, + { + "ordinal": 15, + "name": "error", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "enabled", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false + ] + }, + "hash": "f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357" +} diff --git a/backend/.sqlx/query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json b/backend/.sqlx/query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json similarity index 64% rename from backend/.sqlx/query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json rename to backend/.sqlx/query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json index b905255754..a97a131baa 100644 --- a/backend/.sqlx/query-07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5.json +++ b/backend/.sqlx/query-f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by)\n VALUES ($1, $2, $3, $4, $5, $6, $7)", + "query": "\n INSERT INTO \n capture (\n workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ", "describe": { "columns": [], "parameters": { @@ -21,7 +21,8 @@ "nats", "postgres", "sqs", - "mqtt" + "mqtt", + "gcp" ] } } @@ -33,5 +34,5 @@ }, "nullable": [] }, - "hash": "07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5" + "hash": "f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946" } diff --git a/backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json b/backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json new file mode 100644 index 0000000000..d47bb3fd68 --- /dev/null +++ b/backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE \n gcp_trigger \n SET \n enabled = FALSE, \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5" +} diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json index 6ebd36cf07..ab8340f5c8 100644 --- a/backend/.vscode/settings.json +++ b/backend/.vscode/settings.json @@ -11,5 +11,5 @@ "remote.autoForwardPorts": true, "conventionalCommits.scopes": [ "restructring triggers, decoding trigger message on work" - ] + ], } diff --git a/backend/Cargo.lock b/backend/Cargo.lock index ca8c170ad0..46ef0b5b2d 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -554,6 +554,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-compression" version = "0.4.19" @@ -4602,6 +4613,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "5.4.0" @@ -5347,6 +5364,94 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "google-cloud-auth" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57a13fbacc5e9c41ded3ad8d0373175a6b7a6ad430d99e89d314ac121b7ab06" +dependencies = [ + "async-trait", + "base64 0.21.7", + "google-cloud-metadata", + "google-cloud-token", + "home", + "jsonwebtoken 9.3.1", + "reqwest 0.12.15", + "serde", + "serde_json", + "thiserror 1.0.69", + "time", + "tokio", + "tracing", + "urlencoding", +] + +[[package]] +name = "google-cloud-gax" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de13e62d7e0ffc3eb40a0113ddf753cf6ec741be739164442b08893db4f9bfca" +dependencies = [ + "google-cloud-token", + "http 1.3.1", + "thiserror 1.0.69", + "tokio", + "tokio-retry2", + "tonic", + "tower 0.4.13", + "tracing", +] + +[[package]] +name = "google-cloud-googleapis" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886aa8ec755382a1fdf4651f6e6ec01f2f3bf49f2cb0f068b9a74cafd574a715" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + +[[package]] +name = "google-cloud-metadata" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d901aeb453fd80e51d64df4ee005014f6cf39f2d736dd64f7239c132d9d39a6a" +dependencies = [ + "reqwest 0.12.15", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "google-cloud-pubsub" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebc6e7327e49a66ffb40508c673b7643191bd6b509530193bda97f09272cdcf" +dependencies = [ + "async-channel", + "async-stream", + "google-cloud-auth", + "google-cloud-gax", + "google-cloud-googleapis", + "google-cloud-token", + "prost-types", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "google-cloud-token" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c12ba8b21d128a2ce8585955246977fbce4415f680ebf9199b6f9d6d725f" +dependencies = [ + "async-trait", +] + [[package]] name = "gosyn" version = "0.2.9" @@ -6427,6 +6532,21 @@ dependencies = [ "simple_asn1", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "pem 3.0.5", + "ring 0.17.14", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "junction" version = "1.2.0" @@ -11025,7 +11145,7 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener", + "event-listener 5.4.0", "futures-core", "futures-intrusive", "futures-io", @@ -12447,6 +12567,16 @@ dependencies = [ "whoami", ] +[[package]] +name = "tokio-retry2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1264d076dd34560544a2799e40e457bd07c43d30f4a845686b031bcd8455c84f" +dependencies = [ + "pin-project", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -12624,6 +12754,7 @@ dependencies = [ "axum", "base64 0.22.1", "bytes", + "flate2", "h2 0.4.8", "http 1.3.1", "http-body 1.0.1", @@ -12644,6 +12775,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", + "webpki-roots", ] [[package]] @@ -13843,6 +13975,8 @@ dependencies = [ "datafusion", "futures", "git-version", + "google-cloud-googleapis", + "google-cloud-pubsub", "half", "hex", "hf-hub", @@ -13850,7 +13984,7 @@ dependencies = [ "http 1.3.1", "hyper 1.6.0", "itertools 0.14.0", - "jsonwebtoken", + "jsonwebtoken 8.3.0", "lazy_static", "magic-crypt", "mail-parser", @@ -13893,6 +14027,7 @@ dependencies = [ "tokio-tar", "tokio-tungstenite", "tokio-util", + "tonic", "tower 0.5.2", "tower-cookies", "tower-http", @@ -13982,7 +14117,7 @@ dependencies = [ "hyper 1.6.0", "indexmap 2.8.0", "itertools 0.14.0", - "jsonwebtoken", + "jsonwebtoken 8.3.0", "lazy_static", "magic-crypt", "mail-send", @@ -14350,7 +14485,7 @@ dependencies = [ "git-version", "hex", "itertools 0.14.0", - "jsonwebtoken", + "jsonwebtoken 8.3.0", "lazy_static", "mappable-rc", "mysql_async", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 561758cab2..4ca7a5fa49 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -69,13 +69,14 @@ nats = ["windmill-api/nats"] otel = ["windmill-common/otel", "windmill-worker/otel"] dind = ["windmill-worker/dind"] websocket = ["windmill-api/websocket"] +http_trigger = ["windmill-api/http_trigger"] postgres_trigger = ["windmill-api/postgres_trigger"] mqtt_trigger = ["windmill-api/mqtt_trigger"] sqs_trigger = ["windmill-api/sqs_trigger"] +gcp_trigger = ["windmill-api/gcp_trigger"] smtp = ["windmill-api/smtp", "windmill-common/smtp"] license = ["windmill-api/license"] oauth2 = ["windmill-api/oauth2"] -http_trigger = ["windmill-api/http_trigger"] zip = ["windmill-api/zip"] static_frontend = ["windmill-api/static_frontend"] scoped_cache = ["windmill-common/scoped_cache"] @@ -242,6 +243,8 @@ deno_runtime = { version = "0.198.0", features = ["transpile"] } deno_telemetry = "0.12.0" deno_error = "=0.5.5" +google-cloud-pubsub = "0.30.0" +google-cloud-googleapis = {version = "0.16.1", features = ["pubsub"]} # TODO: remove once deno fixes the issue on their end # https://github.com/denoland/deno/issues/28557 winapi = { version = "0.3.9", features = ["sysinfoapi"] } diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 48d40a142a..b9a3d2881d 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -0706783f5ebc6fad0f26cb1c0ba52fe1deeeb168 +85c37983ffb8f622458425c182613206625c6cee diff --git a/backend/migrations/20250323135044_add-gcp-trigger-table.down.sql b/backend/migrations/20250323135044_add-gcp-trigger-table.down.sql new file mode 100644 index 0000000000..94e32f5962 --- /dev/null +++ b/backend/migrations/20250323135044_add-gcp-trigger-table.down.sql @@ -0,0 +1,3 @@ +-- Add down migration script here +DROP TABLE gcp_trigger; +DROP TYPE DELIVERY_MODE; \ No newline at end of file diff --git a/backend/migrations/20250323135044_add-gcp-trigger-table.up.sql b/backend/migrations/20250323135044_add-gcp-trigger-table.up.sql new file mode 100644 index 0000000000..2098d27e69 --- /dev/null +++ b/backend/migrations/20250323135044_add-gcp-trigger-table.up.sql @@ -0,0 +1,80 @@ +-- Add up migration script here + +ALTER TYPE TRIGGER_KIND ADD VALUE IF NOT EXISTS 'gcp'; +CREATE TYPE DELIVERY_MODE AS ENUM ('push', 'pull'); + +CREATE TABLE gcp_trigger ( + gcp_resource_path VARCHAR(255) NOT NULL, + topic_id VARCHAR(255) NOT NULL CHECK ( + CHAR_LENGTH(topic_id) BETWEEN 3 AND 255 + ), + subscription_id VARCHAR(255) NOT NULL CHECK ( + CHAR_LENGTH(subscription_id) BETWEEN 3 AND 255 + ), + delivery_type DELIVERY_MODE NOT NULL, + delivery_config JSONB NULL CHECK (delivery_type != 'push'::DELIVERY_MODE OR (delivery_config IS NOT NULL)), + path VARCHAR(255) NOT NULL, + script_path VARCHAR(255) NOT NULL, + is_flow BOOLEAN NOT NULL, + workspace_id VARCHAR(50) NOT NULL, + edited_by VARCHAR(50) NOT NULL, + email VARCHAR(255) NOT NULL, + edited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + extra_perms JSONB NOT NULL DEFAULT '{}', + server_id VARCHAR(50), + last_server_ping TIMESTAMPTZ, + error TEXT, + enabled BOOLEAN NOT NULL, + PRIMARY KEY (path, workspace_id) +); + +CREATE UNIQUE INDEX unique_subscription_per_gcp_resource +ON gcp_trigger (subscription_id, gcp_resource_path, workspace_id); + +GRANT ALL ON gcp_trigger TO windmill_user; +GRANT ALL ON gcp_trigger TO windmill_admin; + +ALTER TABLE gcp_trigger ENABLE ROW LEVEL SECURITY; + +CREATE POLICY admin_policy ON gcp_trigger FOR ALL TO windmill_admin USING (true); + +CREATE POLICY see_folder_extra_perms_user_select ON gcp_trigger FOR SELECT TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_insert ON gcp_trigger FOR INSERT TO windmill_user +WITH CHECK (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_update ON gcp_trigger FOR UPDATE TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); +CREATE POLICY see_folder_extra_perms_user_delete ON gcp_trigger FOR DELETE TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[])); + +CREATE POLICY see_own ON gcp_trigger FOR ALL TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'u' AND SPLIT_PART(gcp_trigger.path, '/', 2) = current_setting('session.user')); +CREATE POLICY see_member ON gcp_trigger FOR ALL TO windmill_user +USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'g' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.groups'), ',')::text[])); + +CREATE POLICY see_extra_perms_user_select ON gcp_trigger FOR SELECT TO windmill_user +USING (extra_perms ? CONCAT('u/', current_setting('session.user'))); +CREATE POLICY see_extra_perms_user_insert ON gcp_trigger FOR INSERT TO windmill_user +WITH CHECK ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); +CREATE POLICY see_extra_perms_user_update ON gcp_trigger FOR UPDATE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); +CREATE POLICY see_extra_perms_user_delete ON gcp_trigger FOR DELETE TO windmill_user +USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean); + +CREATE POLICY see_extra_perms_groups_select ON gcp_trigger FOR SELECT TO windmill_user +USING (extra_perms ?| regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]); +CREATE POLICY see_extra_perms_groups_insert ON gcp_trigger FOR INSERT TO windmill_user +WITH CHECK (exists( + SELECT key, value FROM jsonb_each_text(extra_perms) + WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]) + AND value::boolean)); +CREATE POLICY see_extra_perms_groups_update ON gcp_trigger FOR UPDATE TO windmill_user +USING (exists( + SELECT key, value FROM jsonb_each_text(extra_perms) + WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]) + AND value::boolean)); +CREATE POLICY see_extra_perms_groups_delete ON gcp_trigger FOR DELETE TO windmill_user +USING (exists( + SELECT key, value FROM jsonb_each_text(extra_perms) + WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]) + AND value::boolean)); \ No newline at end of file diff --git a/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql new file mode 100644 index 0000000000..cdf8530b35 --- /dev/null +++ b/backend/migrations/20250323162033_add-missing-trigger-kind-to-job-trigger-kind-type.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'sqs'; +ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'gcp'; diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index 795e4319e2..a6874a0b3d 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -13,7 +13,7 @@ use std::{ use chrono::{NaiveDateTime, Utc}; use futures::{stream::FuturesUnordered, StreamExt}; -use serde::{de::DeserializeOwned, Deserializer}; +use serde::de::DeserializeOwned; use sqlx::{Pool, Postgres}; use tokio::{ join, @@ -34,6 +34,7 @@ use windmill_common::ee::{jobs_waiting_alerts, worker_groups_alerts}; #[cfg(feature = "oauth2")] use windmill_common::global_settings::OAUTH_SETTING; use windmill_common::{ + utils::empty_string_as_none, agent_workers::DECODED_AGENT_TOKEN, auth::create_token_for_owner, ee::CriticalErrorChannel, error, flow_status::{FlowStatus, FlowStatusModule}, global_settings::{ BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING, CRITICAL_ERROR_CHANNELS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING, @@ -46,7 +47,7 @@ use windmill_common::{ SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, TIMEOUT_WAIT_RESULT_SETTING, }, indexer::load_indexer_config, jobs::QueuedJob, jwt::JWT_SECRET, oauth2::REQUIRE_PREEXISTING_USER_FOR_OAUTH, server::load_smtp_config, tracing_init::JSON_FMT, users::truncate_token, utils::{now_from_db, rd_string, report_critical_error, Mode}, worker::{ load_worker_config, reload_custom_tags_setting, store_pull_query, store_suspended_pull_query, update_min_version, Connection, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, INDEXER_CONFIG, SCRIPT_TOKEN_EXPIRY, SMTP_CONFIG, TMP_DIR, WORKER_CONFIG, WORKER_GROUP - }, KillpillSender, BASE_URL, CRITICAL_ALERT_MUTE_UI_ENABLED, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL, JOB_RETENTION_SECS, METRICS_DEBUG_ENABLED, METRICS_ENABLED, MONITOR_LOGS_ON_OBJECT_STORE, OTEL_LOGS_ENABLED, OTEL_METRICS_ENABLED, OTEL_TRACING_ENABLED, SERVICE_LOG_RETENTION_SECS + }, KillpillSender, BASE_URL, CRITICAL_ALERT_MUTE_UI_ENABLED, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL, JOB_RETENTION_SECS, METRICS_DEBUG_ENABLED, METRICS_ENABLED, MONITOR_LOGS_ON_OBJECT_STORE, OTEL_LOGS_ENABLED, OTEL_METRICS_ENABLED, OTEL_TRACING_ENABLED, SERVICE_LOG_RETENTION_SECS, }; use windmill_queue::{cancel_job, MiniPulledJob, SameWorkerPayload}; use windmill_worker::{ @@ -221,14 +222,6 @@ pub async fn load_metrics_enabled(conn: &Connection) -> error::Result<()> { Ok(()) } -fn empty_string_as_none<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let option = as serde::Deserialize>::deserialize(deserializer)?; - Ok(option.filter(|s| !s.is_empty())) -} - #[derive(serde::Deserialize)] struct OtelSetting { metrics_enabled: Option, diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml index e762e82429..c3d695f96e 100644 --- a/backend/windmill-api/Cargo.toml +++ b/backend/windmill-api/Cargo.toml @@ -32,6 +32,7 @@ static_frontend = ["dep:rust-embed"] postgres_trigger = ["dep:rust-postgres", "dep:pg_escape", "dep:byteorder", "dep:thiserror", "dep:rust_decimal", "dep:rust-postgres-native-tls"] mqtt_trigger = ["dep:thiserror", "dep:rumqttc"] sqs_trigger = ["dep:aws-sdk-sqs", "dep:thiserror", "dep:aws-config"] +gcp_trigger = ["dep:thiserror", "dep:google-cloud-pubsub", "dep:google-cloud-googleapis", "dep:tonic"] cloud = ["windmill-common/cloud"] [dependencies] @@ -129,4 +130,7 @@ rust_decimal = { workspace = true, optional = true } rust-postgres-native-tls = { workspace = true, optional = true} rumqttc = { workspace = true, optional = true } aws-sdk-sqs = { workspace = true, optional = true } -aws-config = { workspace = true, optional = true} +aws-config = { workspace = true, optional = true } +google-cloud-pubsub = { workspace = true, optional = true } +google-cloud-googleapis = { workspace = true , optional = true } +tonic = { workspace = true, optional = true } \ No newline at end of file diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index c7d905e15b..81b1b3759b 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -2702,6 +2702,8 @@ paths: type: boolean mqtt_used: type: boolean + gcp_used: + type: boolean sqs_used: type: boolean required: @@ -2711,6 +2713,7 @@ paths: - nats_used - postgres_used - mqtt_used + - gcp_used - sqs_used /w/{workspace}/users/list: get: @@ -9222,6 +9225,264 @@ paths: schema: type: string + /w/{workspace}/gcp_triggers/create: + post: + summary: create gcp trigger + operationId: createGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: new gcp trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/NewGcpTrigger" + responses: + "201": + description: gcp trigger created + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/update/{path}: + post: + summary: update gcp trigger + operationId: updateGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated trigger + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/EditGcpTrigger" + responses: + "200": + description: gcp trigger updated + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/delete/{path}: + delete: + summary: delete gcp trigger + operationId: deleteGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: gcp trigger deleted + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/get/{path}: + get: + summary: get gcp trigger + operationId: getGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: gcp trigger deleted + content: + application/json: + schema: + $ref: "#/components/schemas/GcpTrigger" + + /w/{workspace}/gcp_triggers/list: + get: + summary: list gcp triggers + operationId: listGcpTriggers + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + required: true + - $ref: "#/components/parameters/Page" + - $ref: "#/components/parameters/PerPage" + - name: path + description: filter by path + in: query + schema: + type: string + - name: is_flow + in: query + schema: + type: boolean + - name: path_start + in: query + schema: + type: string + responses: + "200": + description: gcp trigger list + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/GcpTrigger" + + /w/{workspace}/gcp_triggers/exists/{path}: + get: + summary: does gcp trigger exists + operationId: existsGcpTrigger + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: gcp trigger exists + content: + application/json: + schema: + type: boolean + + /w/{workspace}/gcp_triggers/setenabled/{path}: + post: + summary: set enabled gcp trigger + operationId: setGcpTriggerEnabled + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: updated gcp trigger enable + required: true + content: + application/json: + schema: + type: object + properties: + enabled: + type: boolean + required: + - enabled + responses: + "200": + description: gcp trigger enabled set + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/test: + post: + summary: test gcp connection + operationId: testGcpConnection + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: test gcp connection + required: true + content: + application/json: + schema: + type: object + properties: + connection: + type: object + required: + - connection + responses: + "200": + description: try to connect to a gcp broker + content: + text/plain: + schema: + type: string + + + /w/{workspace}/gcp_triggers/subscriptions/delete/{path}: + delete: + summary: delete gcp trigger + operationId: deleteGcpSubscription + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: args to delete subscription from google cloud + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DeleteGcpSubscription" + responses: + "200": + description: gcp trigger deleted + content: + text/plain: + schema: + type: string + + /w/{workspace}/gcp_triggers/topics/list/{path}: + get: + summary: list all topics of google cloud service + operationId: listGoogleTopics + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + responses: + "200": + description: get all google topics + content: + application/json: + schema: + type: array + items: + type: string + + /w/{workspace}/gcp_triggers/subscriptions/list/{path}: + post: + summary: list all subscription of a give topic from google cloud service + operationId: listAllTGoogleTopicSubscriptions + tags: + - gcp_trigger + parameters: + - $ref: "#/components/parameters/WorkspaceId" + - $ref: "#/components/parameters/Path" + requestBody: + description: args to get subscription's topic from google cloud + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/GetAllTopicSubscription" + responses: + "200": + description: get all google topic subscriptions name + content: + application/json: + schema: + type: array + items: + type: string /w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}: get: @@ -10563,6 +10824,7 @@ paths: nats_trigger, postgres_trigger, mqtt_trigger, + gcp_trigger, sqs_trigger ] responses: @@ -10606,6 +10868,7 @@ paths: nats_trigger, postgres_trigger, mqtt_trigger, + gcp_trigger, sqs_trigger ] requestBody: @@ -10660,6 +10923,7 @@ paths: nats_trigger, postgres_trigger, mqtt_trigger, + gcp_trigger, sqs_trigger ] requestBody: @@ -10712,6 +10976,10 @@ paths: responses: "200": description: capture config set + content: + application/json: + schema: + type: object /w/{workspace}/capture/ping_config/{trigger_kind}/{runnable_kind}/{path}: post: @@ -14190,6 +14458,8 @@ components: type: number mqtt_count: type: number + gcp_count: + type: number sqs_count: type: number @@ -14474,6 +14744,173 @@ components: - subscribe_topics - mqtt_resource_path + DeliveryType: + type: string + enum: + - push + - pull + + PushConfig: + type: object + properties: + audience: + type: string + authenticate: + type: boolean + base_endpoint: + type: string + required: + - authenticate + - base_endpoint + + GcpTrigger: + allOf: + - $ref: "#/components/schemas/TriggerExtraProperty" + type: object + properties: + gcp_resource_path: + type: string + topic_id: + type: string + subscription_id: + type: string + server_id: + type: string + delivery_type: + $ref: "#/components/schemas/DeliveryType" + delivery_config: + $ref: "#/components/schemas/PushConfig" + last_server_ping: + type: string + format: date-time + error: + type: string + enabled: + type: boolean + required: + - gcp_resource_path + - topic_id + - subscription_id + - enabled + - delivery_type + + SubscriptionMode: + type: string + enum: + - existing + - create_update + description: "The mode of subscription. 'existing' means using an existing GCP subscription, while 'create_update' involves creating or updating a new subscription." + + GcpExistingSubscription: + type: object + properties: + subscription_id: + type: string + base_endpoint: + type: string + required: + - subscription_id + - base_endpoint + + GcpCreateUpdateSubscription: + type: object + properties: + subscription_id: + type: string + delivery_type: + $ref: "#/components/schemas/DeliveryType" + delivery_config: + $ref: "#/components/schemas/PushConfig" + required: + - delivery_type + + + GcpSubscriptionModeConfig: + type: object + properties: + subscription_mode: + $ref: "#/components/schemas/SubscriptionMode" + required: + - subscription_mode + allOf: + - oneOf: + - $ref: "#/components/schemas/GcpExistingSubscription" + - $ref: "#/components/schemas/GcpCreateUpdateSubscription" + description: | + "This is a union type representing the subscription mode. + - 'existing': Represents an existing GCP subscription, and should be accompanied by an 'ExistingGcpSubscription' object. + - 'create_update': Represents a new or updated GCP subscription, and should be accompanied by a 'CreateUpdateConfig' object." + + NewGcpTrigger: + type: object + properties: + gcp_resource_path: + type: string + topic_id: + type: string + subscription_mode: + $ref: "#/components/schemas/GcpSubscriptionModeConfig" + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: + - path + - script_path + - is_flow + - gcp_resource_path + - topic_id + - subscription_mode + + EditGcpTrigger: + type: object + properties: + gcp_resource_path: + type: string + topic_id: + type: string + subscription_mode: + $ref: "#/components/schemas/GcpSubscriptionModeConfig" + path: + type: string + script_path: + type: string + is_flow: + type: boolean + enabled: + type: boolean + required: + - path + - script_path + - is_flow + - enabled + - mqtt_resource_path + - subscription_id + - delivery_type + - topic_id + - subscription_mode + + GetAllTopicSubscription: + type: object + properties: + topic_id: + type: string + required: + - topic_id + + + DeleteGcpSubscription: + type: object + properties: + subscription_id: + type: string + required: + - subscription_id + SqsTrigger: allOf: - $ref: "#/components/schemas/TriggerExtraProperty" @@ -15859,7 +16296,7 @@ components: CaptureTriggerKind: type: string - enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt] + enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt, gcp] Capture: type: object diff --git a/backend/windmill-api/src/auth.rs b/backend/windmill-api/src/auth.rs index b0a18112d4..8175e0eae5 100644 --- a/backend/windmill-api/src/auth.rs +++ b/backend/windmill-api/src/auth.rs @@ -509,7 +509,6 @@ where .map(|x| x.0) .unwrap_or_default(); let path_vec: Vec<&str> = original_uri.path().split("/").collect(); - let workspace_id = if path_vec.len() >= 4 && path_vec[0] == "" && path_vec[2] == "w" { Some(path_vec[3].to_owned()) } else { diff --git a/backend/windmill-api/src/capture.rs b/backend/windmill-api/src/capture.rs index dfe0ec6005..93a11752d7 100644 --- a/backend/windmill-api/src/capture.rs +++ b/backend/windmill-api/src/capture.rs @@ -7,34 +7,47 @@ */ #[cfg(feature = "http_trigger")] -use crate::http_triggers::{build_http_trigger_extra, HttpMethod}; +use { + crate::{ + args::try_from_request_body, + http_triggers::{build_http_trigger_extra, HttpMethod}, + }, + axum::response::{IntoResponse, Response}, + std::collections::HashMap, +}; + +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +use crate::gcp_triggers_ee::{ + manage_google_subscription, process_google_push_request, validate_jwt_token, SubscriptionMode, +}; + +#[cfg(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") +))] +use { + axum::extract::Request, http::HeaderMap, serde::de::DeserializeOwned, + windmill_common::error::Error, +}; + #[cfg(all(feature = "enterprise", feature = "kafka"))] use crate::kafka_triggers_ee::KafkaTriggerConfigConnection; + #[cfg(feature = "mqtt_trigger")] use crate::mqtt_triggers::{MqttClientVersion, MqttV3Config, MqttV5Config, SubscribeTopic}; + #[cfg(all(feature = "enterprise", feature = "nats"))] use crate::nats_triggers_ee::NatsTriggerConfigConnection; + #[cfg(feature = "postgres_trigger")] -use crate::postgres_triggers::{ - create_logical_replication_slot_query, create_publication_query, drop_publication_query, - generate_random_string, get_database_connection, PublicationData, +use { + crate::postgres_triggers::{ + create_logical_replication_slot_query, create_publication_query, drop_publication_query, + generate_random_string, get_database_connection, PublicationData, + }, + itertools::Itertools, + pg_escape::quote_literal, }; -#[cfg(feature = "http_trigger")] -use axum::extract::Request; -#[cfg(feature = "http_trigger")] -use axum::response::IntoResponse; -#[cfg(feature = "http_trigger")] -use http::HeaderMap; -#[cfg(feature = "postgres_trigger")] -use itertools::Itertools; -#[cfg(feature = "postgres_trigger")] -use pg_escape::quote_literal; -#[cfg(feature = "http_trigger")] -use serde::de::DeserializeOwned; -#[cfg(feature = "http_trigger")] -use std::collections::HashMap; -#[cfg(feature = "http_trigger")] -use windmill_common::error::Error; use crate::{ args::WebhookArgs, @@ -42,23 +55,26 @@ use crate::{ users::fetch_api_authed, utils::RunnableKind, }; + use axum::{ extract::{Extension, Path, Query}, routing::{delete, get, head, post}, Json, Router, }; + use hyper::StatusCode; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; use sqlx::types::Json as SqlxJson; + use windmill_common::{ db::UserDB, error::{JsonResult, Result}, utils::{not_found_if_none, paginate, Pagination, StripPath}, worker::{to_raw_value, CLOUD_HOSTED}, }; -use windmill_queue::TriggerKind; -use windmill_queue::{PushArgs, PushArgsOwned}; + +use windmill_queue::{PushArgs, PushArgsOwned, TriggerKind}; const KEEP_LAST: i64 = 20; @@ -85,14 +101,26 @@ pub fn workspaced_unauthed_service() -> Router { head(|| async {}).post(webhook_payload), ); - #[cfg(feature = "http_trigger")] + #[cfg(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") + ))] { - router.route("/http/:runnable_kind/:path/*route_path", { + #[cfg(feature = "http_trigger")] + let router = router.route("/http/:runnable_kind/:path/*route_path", { head(|| async {}).fallback(http_payload) - }) + }); + + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + let router = router.route("/gcp/:runnable_kind/*path", post(gcp_payload)); + + router } - #[cfg(not(feature = "http_trigger"))] + #[cfg(not(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") + )))] { router } @@ -124,6 +152,15 @@ pub struct SqsTriggerConfig { pub message_attributes: Option>, } +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +#[derive(Debug, Serialize, Deserialize)] +pub struct GcpTriggerConfig { + pub gcp_resource_path: String, + #[serde(flatten)] + pub subscription_mode: SubscriptionMode, + pub topic_id: String, +} + #[cfg(all(feature = "enterprise", feature = "nats"))] #[derive(Serialize, Deserialize)] pub struct NatsTriggerConfig { @@ -181,6 +218,8 @@ enum TriggerConfig { Nats(NatsTriggerConfig), #[cfg(feature = "mqtt_trigger")] Mqtt(MqttTriggerConfig), + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + Gcp(GcpTriggerConfig), } #[derive(Serialize, Deserialize)] @@ -208,15 +247,26 @@ async fn get_configs( let configs = sqlx::query_as!( CaptureConfig, - r#"SELECT trigger_config as "trigger_config: _", trigger_kind as "trigger_kind: _", error, last_server_ping - FROM capture_config - WHERE workspace_id = $1 AND path = $2 AND is_flow = $3"#, + r#" + SELECT + trigger_config AS "trigger_config: _", + trigger_kind AS "trigger_kind: _", + error, + last_server_ping + FROM + capture_config + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + "#, &w_id, &path.to_path(), matches!(runnable_kind, RunnableKind::Flow), ) .fetch_all(&mut *tx) .await?; + tx.commit().await?; Ok(Json(configs)) @@ -284,33 +334,100 @@ async fn set_postgres_trigger_config( Ok(capture_config) } +#[inline] +#[cfg(not(feature = "postgres_trigger"))] +async fn set_postgres_trigger_config( + _w_id: &str, + _authed: ApiAuthed, + _db: &DB, + _user_db: UserDB, + capture_config: NewCaptureConfig, +) -> Result { + Ok(capture_config) +} + +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +async fn set_gcp_trigger_config( + w_id: &str, + authed: ApiAuthed, + db: &DB, + mut capture_config: NewCaptureConfig, +) -> Result { + let Some(TriggerConfig::Gcp(mut gcp_config)) = capture_config.trigger_config else { + return Err(windmill_common::error::Error::BadRequest( + "Invalid GCP Pub/Sub config".to_string(), + )); + }; + + let config = manage_google_subscription( + authed, + db, + w_id, + &gcp_config.gcp_resource_path, + &capture_config.path, + &gcp_config.topic_id, + gcp_config.subscription_mode, + ) + .await?; + + gcp_config.subscription_mode = SubscriptionMode::CreateUpdate(config); + capture_config.trigger_config = Some(TriggerConfig::Gcp(gcp_config)); + + Ok(capture_config) +} + +#[inline] +#[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))] +async fn set_gcp_trigger_config( + _w_id: &str, + _authed: ApiAuthed, + _db: &DB, + capture_config: NewCaptureConfig, +) -> Result { + Ok(capture_config) +} + async fn set_config( authed: ApiAuthed, Extension(user_db): Extension, - #[cfg(feature = "postgres_trigger")] Extension(db): Extension, + Extension(db): Extension, Path(w_id): Path, Json(nc): Json, -) -> Result<()> { - #[cfg(feature = "postgres_trigger")] - let nc = if let TriggerKind::Postgres = nc.trigger_kind { - set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await? - } else { - nc +) -> JsonResult> { + let nc = match nc.trigger_kind { + TriggerKind::Postgres => { + set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await? + } + TriggerKind::Gcp => set_gcp_trigger_config(&w_id, authed.clone(), &db, nc).await?, + _ => nc, }; let mut tx = user_db.begin(&authed).await?; sqlx::query!( - "INSERT INTO capture_config - (workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email) - VALUES ($1, $2, $3, $4, $5, $6, $7) + r#" + INSERT INTO capture_config ( + workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email + ) + VALUES ( + $1, $2, $3, $4, $5, $6, $7 + ) ON CONFLICT (workspace_id, path, is_flow, trigger_kind) - DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, error = NULL", + DO UPDATE + SET + trigger_config = $5, + owner = $6, + email = $7, + server_id = NULL, + error = NULL + "#, &w_id, &nc.path, nc.is_flow, nc.trigger_kind as TriggerKind, - nc.trigger_config.map(|x| SqlxJson(to_raw_value(&x))) as Option>>, + nc.trigger_config + .as_ref() + .map(|x| SqlxJson(to_raw_value(&x))) as Option>>, &authed.username, &authed.email, ) @@ -319,7 +436,7 @@ async fn set_config( tx.commit().await?; - Ok(()) + Ok(Json(nc.trigger_config)) } async fn ping_config( @@ -333,8 +450,19 @@ async fn ping_config( )>, ) -> Result<()> { let mut tx = user_db.begin(&authed).await?; + sqlx::query!( - "UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4", + r#" + UPDATE + capture_config + SET + last_client_ping = NOW() + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + AND trigger_kind = $4 + "#, &w_id, &path.to_path(), matches!(runnable_kind, RunnableKind::Flow), @@ -342,6 +470,7 @@ async fn ping_config( ) .execute(&mut *tx) .await?; + tx.commit().await?; Ok(()) } @@ -374,14 +503,28 @@ async fn list_captures( let captures = sqlx::query_as!( Capture, - r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", CASE WHEN pg_column_size(payload) < 40000 THEN payload ELSE '"WINDMILL_TOO_BIG"'::jsonb END as "payload!: _", trigger_extra as "trigger_extra: _" - FROM capture - WHERE workspace_id = $1 - AND path = $2 AND is_flow = $3 + r#" + SELECT + id, + created_at, + trigger_kind AS "trigger_kind: _", + CASE + WHEN pg_column_size(payload) < 40000 THEN payload + ELSE '"WINDMILL_TOO_BIG"'::jsonb + END AS "payload!: _", + trigger_extra AS "trigger_extra: _" + FROM + capture + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 AND ($4::trigger_kind IS NULL OR trigger_kind = $4) - ORDER BY created_at DESC + ORDER BY + created_at DESC OFFSET $5 - LIMIT $6"#, + LIMIT $6 + "#, &w_id, &path.to_path(), matches!(runnable_kind, RunnableKind::Flow), @@ -403,14 +546,28 @@ async fn get_capture( Path((w_id, id)): Path<(String, i64)>, ) -> JsonResult { let mut tx = user_db.begin(&authed).await?; + let capture = sqlx::query_as!( Capture, - r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", payload as "payload!: _", trigger_extra as "trigger_extra: _" FROM capture WHERE id = $1 AND workspace_id = $2"#, + r#" + SELECT + id, + created_at, + trigger_kind AS "trigger_kind: _", + payload AS "payload!: _", + trigger_extra AS "trigger_extra: _" + FROM + capture + WHERE + id = $1 + AND workspace_id = $2 + "#, id, &w_id, ) .fetch_one(&mut *tx) - .await?; + .await?; + tx.commit().await?; Ok(Json(capture)) } @@ -421,9 +578,17 @@ async fn delete_capture( Path((_, id)): Path<(String, i64)>, ) -> Result<()> { let mut tx = user_db.begin(&authed).await?; - sqlx::query!("DELETE FROM capture WHERE id = $1", id) - .execute(&mut *tx) - .await?; + sqlx::query!( + r#" + DELETE FROM + capture + WHERE + id = $1 + "#, + id + ) + .execute(&mut *tx) + .await?; tx.commit().await?; Ok(()) } @@ -441,8 +606,18 @@ async fn move_captures_and_configs( ) -> Result<()> { let mut tx = user_db.begin(&authed).await?; let old_path = old_path.to_path(); + sqlx::query!( - "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", + r#" + UPDATE + capture_config + SET + path = $1 + WHERE + path = $2 + AND workspace_id = $3 + AND is_flow = $4 + "#, body.new_path, old_path, &w_id, @@ -450,8 +625,18 @@ async fn move_captures_and_configs( ) .execute(&mut *tx) .await?; + sqlx::query!( - "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4", + r#" + UPDATE + capture + SET + path = $1 + WHERE + path = $2 + AND workspace_id = $3 + AND is_flow = $4 + "#, body.new_path, old_path, &w_id, @@ -459,6 +644,7 @@ async fn move_captures_and_configs( ) .execute(&mut *tx) .await?; + tx.commit().await?; Ok(()) } @@ -478,9 +664,19 @@ pub async fn get_active_capture_owner_and_email( ) -> Result<(String, String)> { let capture_config = sqlx::query_as!( ActiveCaptureOwner, - "SELECT owner, email - FROM capture_config - WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'", + r#" + SELECT + owner, + email + FROM + capture_config + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + AND trigger_kind = $4 + AND last_client_ping > NOW() - INTERVAL '10 seconds' + "#, &w_id, &path, is_flow, @@ -498,7 +694,10 @@ pub async fn get_active_capture_owner_and_email( Ok((capture_config.owner, capture_config.email)) } -#[cfg(feature = "http_trigger")] +#[cfg(any( + feature = "http_trigger", + all(feature = "enterprise", feature = "gcp_trigger") +))] async fn get_capture_trigger_config_and_owner( db: &DB, w_id: &str, @@ -512,16 +711,34 @@ async fn get_capture_trigger_config_and_owner( owner: String, email: String, } - let capture_config = sqlx::query_as!( CaptureTriggerConfigAndOwner, - r#"SELECT trigger_config as "trigger_config: _", owner, email - FROM capture_config - WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'"#, + r#" + SELECT + trigger_config AS "trigger_config: _", + owner, + email + FROM + capture_config + WHERE + workspace_id = $1 + AND path = $2 + AND is_flow = $3 + AND trigger_kind = $4 + AND last_client_ping > NOW() - INTERVAL '10 seconds' + AND ( + $5::bool IS FALSE + OR ( + trigger_config IS NOT NULL + AND trigger_config ->> 'delivery_type' = 'push' + ) + ) + "#, &w_id, &path, is_flow, kind as &TriggerKind, + matches!(kind, TriggerKind::Gcp) ) .fetch_optional(db) .await?; @@ -554,17 +771,24 @@ async fn clear_captures_history(db: &DB, w_id: &str) -> Result<()> { if *CLOUD_HOSTED { /* Retain only KEEP_LAST most recent captures in this workspace. */ sqlx::query!( - "DELETE FROM capture - WHERE workspace_id = $1 - AND created_at <= - ( - SELECT created_at - FROM capture - WHERE workspace_id = $1 - ORDER BY created_at DESC - OFFSET $2 - LIMIT 1 - )", + r#" + DELETE FROM + capture + WHERE + workspace_id = $1 + AND created_at <= ( + SELECT + created_at + FROM + capture + WHERE + workspace_id = $1 + ORDER BY + created_at DESC + OFFSET $2 + LIMIT 1 + ) + "#, &w_id, KEEP_LAST, ) @@ -585,8 +809,15 @@ pub async fn insert_capture_payload( owner: &str, ) -> Result<()> { sqlx::query!( - "INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by) - VALUES ($1, $2, $3, $4, $5, $6, $7)", + r#" + INSERT INTO + capture ( + workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by + ) + VALUES ( + $1, $2, $3, $4, $5, $6, $7 + ) + "#, &w_id, path, is_flow, @@ -642,36 +873,74 @@ async fn webhook_payload( Ok(StatusCode::NO_CONTENT) } +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +async fn gcp_payload( + Extension(db): Extension, + Extension(user_db): Extension, + Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, String)>, + headers: HeaderMap, + request: Request, +) -> Result { + let is_flow = matches!(runnable_kind, RunnableKind::Flow); + let (gcp_trigger_config, owner, email): (GcpTriggerConfig, _, _) = + get_capture_trigger_config_and_owner(&db, &w_id, &path, is_flow, &TriggerKind::Gcp).await?; + + let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None).await?; + + let SubscriptionMode::CreateUpdate(config) = &gcp_trigger_config.subscription_mode else { + return Err(Error::BadConfig("Bad config".to_string())); + }; + + validate_jwt_token( + &db, + user_db.clone(), + authed.clone(), + &headers, + &gcp_trigger_config.gcp_resource_path, + &w_id, + config.delivery_config.as_ref().unwrap(), + ) + .await?; + + let (args, extra) = process_google_push_request(headers, request).await?; + + let payload = PushArgsOwned { args, extra: None }; + + let _ = insert_capture_payload( + &db, + &w_id, + &path, + is_flow, + &TriggerKind::Gcp, + payload, + Some(to_raw_value(&extra)), + &owner, + ) + .await?; + + Ok(StatusCode::NO_CONTENT) +} + #[cfg(feature = "http_trigger")] async fn http_payload( Extension(db): Extension, - Path((w_id, kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>, + Path((w_id, runnable_kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>, Query(query): Query>, method: http::Method, headers: HeaderMap, request: Request, -) -> std::result::Result { - use axum::response::Response; - - use crate::args::try_from_request_body; - - let route_path = route_path.to_path(); +) -> std::result::Result { let path = path.replace(".", "/"); - + let is_flow = matches!(runnable_kind, RunnableKind::Flow); + let route_path = route_path.to_path(); let (http_trigger_config, owner, email): (HttpTriggerConfig, _, _) = - get_capture_trigger_config_and_owner( - &db, - &w_id, - &path, - matches!(kind, RunnableKind::Flow), - &TriggerKind::Http, - ) - .await - .map_err(|e| e.into_response())?; + get_capture_trigger_config_and_owner(&db, &w_id, &path, is_flow, &TriggerKind::Http) + .await + .map_err(|e| e.into_response())?; let args = try_from_request_body( request, - &db, + &(), http_trigger_config.raw_string, http_trigger_config.wrap_body, ) @@ -721,7 +990,7 @@ async fn http_payload( &db, &w_id, &path, - matches!(kind, RunnableKind::Flow), + is_flow, &TriggerKind::Http, args, extra, @@ -730,5 +999,5 @@ async fn http_payload( .await .map_err(|e| e.into_response())?; - Ok::<_, Response>(StatusCode::NO_CONTENT) + Ok(StatusCode::NO_CONTENT) } diff --git a/backend/windmill-api/src/gcp_triggers_ee.rs b/backend/windmill-api/src/gcp_triggers_ee.rs new file mode 100644 index 0000000000..ec0a6ec115 --- /dev/null +++ b/backend/windmill-api/src/gcp_triggers_ee.rs @@ -0,0 +1,133 @@ +use crate::db::{ApiAuthed, DB}; +use axum::{extract::Request, Router}; +use http::HeaderMap; +use serde::{Deserialize, Serialize}; +use serde_json::value::RawValue; +use sqlx::prelude::FromRow; +use sqlx::types::Json as SqlxJson; +use std::collections::HashMap; +use windmill_common::db::UserDB; +use windmill_common::{ + error::{Error as WindmillError, Result as WindmillResult}, + utils::empty_string_as_none, +}; + +#[derive(sqlx::Type, Debug, Deserialize, Serialize)] +#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))] +#[sqlx(type_name = "DELIVERY_MODE", rename_all = "lowercase")] +#[allow(unused)] +pub enum DeliveryType { + Pull, + Push, +} + +impl Default for DeliveryType { + fn default() -> Self { + Self::Pull + } +} + +#[derive(FromRow, Deserialize, Serialize, Debug)] +#[allow(unused)] +pub struct PushConfig { + #[serde(deserialize_with = "empty_string_as_none")] + route_path: Option, + #[serde(deserialize_with = "empty_string_as_none")] + audience: Option, + authenticate: bool, + base_endpoint: String, +} +#[derive(Default, Debug, Serialize, Deserialize)] +#[allow(unused)] +pub struct CreateUpdateConfig { + pub delivery_type: DeliveryType, + #[serde(default, deserialize_with = "empty_string_as_none")] + pub subscription_id: Option, + pub delivery_config: Option>, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ExistingGcpSubscription { + pub subscription_id: String, + pub base_endpoint: String, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(tag = "subscription_mode", rename_all = "snake_case")] +pub enum SubscriptionMode { + Existing(ExistingGcpSubscription), + CreateUpdate(CreateUpdateConfig), +} + +pub fn workspaced_service() -> Router { + Router::new() +} + +pub fn start_consuming_gcp_pubsub_event( + _db: DB, + mut _killpill_rx: tokio::sync::broadcast::Receiver<()>, +) -> () { + // implementation is not open source +} + +pub async fn manage_google_subscription( + _authed: ApiAuthed, + _db: &DB, + _workspace_id: &str, + _gcp_resource_path: &str, + _path: &str, + _topic_id: &str, + _subscription_mode: SubscriptionMode, +) -> WindmillResult { + Ok(CreateUpdateConfig::default()) +} + +pub async fn process_google_push_request( + _headers: HeaderMap, + _request: Request, +) -> Result< + ( + HashMap>, + Option>>, + ), + WindmillError, +> { + Ok((HashMap::new(), None)) +} + +pub async fn validate_jwt_token( + _db: &DB, + _user_db: UserDB, + _authed: ApiAuthed, + _headers: &HeaderMap, + _gcp_resource_path: &str, + _workspace_id: &str, + _delivery_config: &PushConfig, +) -> Result<(), windmill_common::error::Error> { + Ok(()) +} + +pub fn gcp_push_route_handler() -> Router { + Router::new() +} + +#[derive(FromRow, Deserialize, Serialize, Debug)] +pub struct GcpTrigger { + pub gcp_resource_path: String, + pub subscription_id: String, + pub delivery_type: DeliveryType, + pub delivery_config: Option>, + pub topic_id: String, + pub path: String, + pub script_path: String, + pub is_flow: bool, + pub workspace_id: String, + pub edited_by: String, + pub email: String, + pub edited_at: chrono::DateTime, + pub extra_perms: Option, + pub error: Option, + pub server_id: Option, + pub last_server_ping: Option>, + pub enabled: bool, +} diff --git a/backend/windmill-api/src/http_trigger_auth.rs b/backend/windmill-api/src/http_trigger_auth.rs index ee60f70efa..fd15927b69 100644 --- a/backend/windmill-api/src/http_trigger_auth.rs +++ b/backend/windmill-api/src/http_trigger_auth.rs @@ -618,7 +618,9 @@ impl AuthenticationMethod { api_key_header, api_key_secret, }) => { - let api_key_to_cmp = headers.try_get_webhook_header(&api_key_header)?; + let api_key_to_cmp = headers + .try_get_webhook_header(&api_key_header) + .map_err(|_| AuthenticationError::InvalidApiKey)?; if api_key_to_cmp != api_key_secret { return Err(AuthenticationError::InvalidApiKey); } @@ -734,7 +736,9 @@ impl IntoResponse for AuthenticationError { ) .into_response() } - AuthenticationError::InvalidApiKey => (StatusCode::FORBIDDEN, self.to_string()), + AuthenticationError::InvalidApiKey => { + return (StatusCode::UNAUTHORIZED, "Unauthorized").into_response() + } }; let body = json!({ "error": error_message }); diff --git a/backend/windmill-api/src/http_triggers.rs b/backend/windmill-api/src/http_triggers.rs index 9e75882f39..fa26406a13 100644 --- a/backend/windmill-api/src/http_triggers.rs +++ b/backend/windmill-api/src/http_triggers.rs @@ -953,7 +953,7 @@ async fn route_job( let args = try_from_request_body( request, - &db, + &(), Some(match trigger.authentication_method { AuthenticationMethod::CustomScript | AuthenticationMethod::Signature => true, _ => trigger.raw_string, diff --git a/backend/windmill-api/src/lib.rs b/backend/windmill-api/src/lib.rs index f5e962aae3..75e67e9abe 100644 --- a/backend/windmill-api/src/lib.rs +++ b/backend/windmill-api/src/lib.rs @@ -89,6 +89,8 @@ mod postgres_triggers; #[cfg(feature = "enterprise")] mod apps_ee; +#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] +mod gcp_triggers_ee; #[cfg(feature = "enterprise")] mod git_sync_ee; #[cfg(feature = "parquet")] @@ -117,6 +119,7 @@ mod slack_approvals; mod smtp_server_ee; #[cfg(all(feature = "enterprise", feature = "sqs_trigger"))] mod sqs_triggers_ee; + mod static_assets; #[cfg(all(feature = "stripe", feature = "enterprise"))] mod stripe_ee; @@ -347,6 +350,18 @@ pub async fn run_server( } }; + let gcp_triggers_service = { + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + gcp_triggers_ee::workspaced_service() + } + + #[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))] + { + Router::new() + } + }; + let sqs_triggers_service = { #[cfg(all(feature = "enterprise", feature = "sqs_trigger"))] { @@ -425,6 +440,12 @@ pub async fn run_server( let sqs_killpill_rx = killpill_rx.resubscribe(); sqs_triggers_ee::start_sqs(db.clone(), sqs_killpill_rx); } + + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + let gcp_killpill_rx = killpill_rx.resubscribe(); + gcp_triggers_ee::start_consuming_gcp_pubsub_event(db.clone(), gcp_killpill_rx); + } } #[cfg(feature = "agent_worker_server")] @@ -488,6 +509,7 @@ pub async fn run_server( .nest("/nats_triggers", nats_triggers_service) .nest("/mqtt_triggers", mqtt_triggers_service) .nest("/sqs_triggers", sqs_triggers_service) + .nest("/gcp_triggers", gcp_triggers_service) .nest("/postgres_triggers", postgres_triggers_service), ) .nest("/workspaces", workspaces::global_service()) @@ -638,6 +660,20 @@ pub async fn run_server( } .layer(from_extractor::()), ) + .nest( + "/gcp/w/:workspace_id", + { + #[cfg(feature = "gcp_trigger")] + { + gcp_triggers_ee::gcp_push_route_handler() + } + #[cfg(not(feature = "gcp_trigger"))] + { + Router::new() + } + } + .layer(from_extractor::()), + ) .route("/version", get(git_v)) .route("/uptodate", get(is_up_to_date)) .route("/ee_license", get(ee_license)) diff --git a/backend/windmill-api/src/resources.rs b/backend/windmill-api/src/resources.rs index 9b5e216047..8a2fab0434 100644 --- a/backend/windmill-api/src/resources.rs +++ b/backend/windmill-api/src/resources.rs @@ -599,11 +599,10 @@ pub async fn transform_json_value<'c>( } Value::Object(mut m) => { for (a, b) in m.clone().into_iter() { - m.insert( - a.clone(), + let v = transform_json_value(authed, user_db.clone(), db, workspace, b, job_id, token) - .await?, - ); + .await?; + m.insert(a.clone(), v); } Ok(Value::Object(m)) } @@ -1212,7 +1211,10 @@ async fn update_resource_type( feature = "http_trigger", feature = "postgres_trigger", feature = "mqtt_trigger", - all(feature = "sqs_trigger", feature = "enterprise") + all( + feature = "enterprise", + any(feature = "sqs_trigger", feature = "gcp_trigger") + ) ))] pub async fn try_get_resource_from_db_as( authed: ApiAuthed, diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index 5282ef7bc6..e12514a69f 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -1307,6 +1307,7 @@ struct UsedTriggers { pub postgres_used: bool, pub mqtt_used: bool, pub sqs_used: bool, + pub gcp_used: bool } async fn get_used_triggers( @@ -1325,7 +1326,8 @@ async fn get_used_triggers( EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as "nats_used!", EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS "postgres_used!", EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS "mqtt_used!", - EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS "sqs_used!" + EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS "sqs_used!", + EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS "gcp_used!" "#, w_id ) diff --git a/backend/windmill-api/src/workspaces_export.rs b/backend/windmill-api/src/workspaces_export.rs index 6ace3e21d4..ac98ae12ec 100644 --- a/backend/windmill-api/src/workspaces_export.rs +++ b/backend/windmill-api/src/workspaces_export.rs @@ -637,6 +637,47 @@ pub(crate) async fn tarball_workspace( } } + #[cfg(all(feature = "enterprise", feature = "gcp_trigger"))] + { + let gcp_triggers = sqlx::query_as!( + crate::gcp_triggers_ee::GcpTrigger, + r#" + SELECT + gcp_resource_path, + subscription_id, + topic_id, + workspace_id, + delivery_type AS "delivery_type: _", + delivery_config AS "delivery_config: _", + path, + script_path, + is_flow, + edited_by, + email, + edited_at, + server_id, + last_server_ping, + extra_perms, + error, + enabled + FROM + gcp_trigger + WHERE + workspace_id = $1 + "#, + &w_id + ) + .fetch_all(&mut *tx) + .await?; + + for trigger in gcp_triggers { + let trigger_str = &to_string_without_metadata(&trigger, false, None).unwrap(); + archive + .write_to_archive(&trigger_str, &format!("{}.gcp_trigger.json", trigger.path)) + .await?; + } + } + #[cfg(all(feature = "enterprise", feature = "nats"))] { let nats_triggers = sqlx::query_as!( diff --git a/backend/windmill-common/src/error.rs b/backend/windmill-common/src/error.rs index 9642f5ee83..feced2b6d5 100644 --- a/backend/windmill-common/src/error.rs +++ b/backend/windmill-common/src/error.rs @@ -22,6 +22,8 @@ pub type JsonResult = std::result::Result, Error>; #[derive(Debug, Error)] pub enum Error { + #[error("Bad gateway: {0}")] + BadGateway(String), #[error("Bad config: {0}")] BadConfig(String), #[error("Connecting to database: {0}")] @@ -76,6 +78,8 @@ pub enum Error { FindPythonError(String), #[error("Problem with arguments: {0}")] ArgumentErr(String), + #[error("{1}")] + Generic(StatusCode, String), } fn prettify_location(location: &'static Location<'static>) -> String { @@ -181,6 +185,8 @@ impl IntoResponse for Error { | Self::BadRequest(_) | Self::AIError(_) | Self::QuotaExceeded(_) => axum::http::StatusCode::BAD_REQUEST, + Self::BadGateway(_) => axum::http::StatusCode::BAD_GATEWAY, + Self::Generic(status_code, _) => status_code, _ => axum::http::StatusCode::INTERNAL_SERVER_ERROR, }; diff --git a/backend/windmill-common/src/utils.rs b/backend/windmill-common/src/utils.rs index ee157db3f0..5018591072 100644 --- a/backend/windmill-common/src/utils.rs +++ b/backend/windmill-common/src/utils.rs @@ -418,16 +418,6 @@ pub async fn report_critical_error( } } -pub fn empty_string_as_none<'de, D>( - deserializer: D, -) -> std::result::Result, D::Error> -where - D: Deserializer<'de>, -{ - let option = as serde::Deserialize>::deserialize(deserializer)?; - Ok(option.filter(|s| !s.is_empty())) -} - pub async fn report_recovered_critical_error( message: String, _db: DB, @@ -478,6 +468,16 @@ pub async fn report_recovered_critical_error( } } +pub fn empty_string_as_none<'de, D>( + deserializer: D, +) -> std::result::Result, D::Error> +where + D: Deserializer<'de>, +{ + let option = as serde::Deserialize>::deserialize(deserializer)?; + Ok(option.filter(|s| !s.is_empty())) +} + pub async fn fetch_mute_workspace(_db: &DB, workspace_id: &str) -> Result { match sqlx::query!( "SELECT mute_critical_alerts FROM workspace_settings WHERE workspace_id = $1", diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 5e744e6d7c..cf0fb8ce8b 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -1952,6 +1952,7 @@ pub enum TriggerKind { Mqtt, Sqs, Postgres, + Gcp } #[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone)] @@ -1968,6 +1969,7 @@ pub enum JobTriggerKind { Sqs, Postgres, Schedule, + Gcp } impl fmt::Display for TriggerKind { @@ -1982,6 +1984,7 @@ impl fmt::Display for TriggerKind { TriggerKind::Mqtt => "mqtt", TriggerKind::Sqs => "sqs", TriggerKind::Postgres => "postgres", + TriggerKind::Gcp => "gcp", }; write!(f, "{}", s) } diff --git a/backend/windmill-worker/src/common.rs b/backend/windmill-worker/src/common.rs index 582b9c3abe..baaaeadc72 100644 --- a/backend/windmill-worker/src/common.rs +++ b/backend/windmill-worker/src/common.rs @@ -33,6 +33,7 @@ use windmill_common::{ use anyhow::{anyhow, bail, Result}; use windmill_queue::MiniPulledJob; +use std::ops::AsyncFn; use std::path::Path; use std::{collections::HashMap, sync::Arc, time::Duration}; diff --git a/backend/windmill-worker/src/mssql_executor.rs b/backend/windmill-worker/src/mssql_executor.rs index aa484753cd..d827e57095 100644 --- a/backend/windmill-worker/src/mssql_executor.rs +++ b/backend/windmill-worker/src/mssql_executor.rs @@ -8,9 +8,11 @@ use tiberius::{AuthMethod, Client, ColumnData, Config, FromSqlOwned, Query, Row, use tokio::net::TcpStream; use tokio_util::compat::TokioAsyncWriteCompatExt; use uuid::Uuid; -use windmill_common::error::to_anyhow; -use windmill_common::error::{self, Error}; -use windmill_common::worker::{to_raw_value, Connection}; +use windmill_common::{ + error::{self, to_anyhow, Error}, + utils::empty_string_as_none, + worker::{to_raw_value, Connection}, +}; use windmill_parser_sql::{parse_db_resource, parse_mssql_sig}; use windmill_queue::MiniPulledJob; use windmill_queue::{append_logs, CanceledBy}; @@ -379,14 +381,6 @@ fn sql_to_json_value(val: ColumnData) -> Result { } } -fn empty_string_as_none<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let option = as serde::Deserialize>::deserialize(deserializer)?; - Ok(option.filter(|s| !s.is_empty())) -} - fn deserialize_aad_token<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, diff --git a/cli/gen/core/OpenAPI.ts b/cli/gen/core/OpenAPI.ts index 86dbabed40..2938820ca7 100644 --- a/cli/gen/core/OpenAPI.ts +++ b/cli/gen/core/OpenAPI.ts @@ -54,7 +54,7 @@ export const OpenAPI: OpenAPIConfig = { PASSWORD: undefined, TOKEN: getEnv("WM_TOKEN"), USERNAME: undefined, - VERSION: '1.479.2', + VERSION: '1.481.0', WITH_CREDENTIALS: true, interceptors: { request: new Interceptors(), diff --git a/cli/gen/services.gen.ts b/cli/gen/services.gen.ts index 9d245968d1..a94a3a544d 100644 --- a/cli/gen/services.gen.ts +++ b/cli/gen/services.gen.ts @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise.ts'; import { OpenAPI } from './core/OpenAPI.ts'; import { request as __request } from './core/request.ts'; -import type { BackendVersionResponse, BackendUptodateResponse, GetLicenseIdResponse, GetOpenApiYamlResponse, GetAuditLogData, GetAuditLogResponse, ListAuditLogsData, ListAuditLogsResponse, LoginData, LoginResponse, LogoutResponse, GetUserData, GetUserResponse, UpdateUserData, UpdateUserResponse, IsOwnerOfPathData, IsOwnerOfPathResponse, SetPasswordData, SetPasswordResponse, SetPasswordForUserData, SetPasswordForUserResponse, SetLoginTypeForUserData, SetLoginTypeForUserResponse, CreateUserGloballyData, CreateUserGloballyResponse, GlobalUserUpdateData, GlobalUserUpdateResponse, GlobalUsernameInfoData, GlobalUsernameInfoResponse, GlobalUserRenameData, GlobalUserRenameResponse, GlobalUserDeleteData, GlobalUserDeleteResponse, GlobalUsersOverwriteData, GlobalUsersOverwriteResponse, GlobalUsersExportResponse, DeleteUserData, DeleteUserResponse, GetGlobalConnectedRepositoriesResponse, ListWorkspacesResponse, IsDomainAllowedResponse, ListUserWorkspacesResponse, ListWorkspacesAsSuperAdminData, ListWorkspacesAsSuperAdminResponse, CreateWorkspaceData, CreateWorkspaceResponse, ExistsWorkspaceData, ExistsWorkspaceResponse, ExistsUsernameData, ExistsUsernameResponse, GetGlobalData, GetGlobalResponse, SetGlobalData, SetGlobalResponse, GetLocalResponse, TestSmtpData, TestSmtpResponse, TestCriticalChannelsData, TestCriticalChannelsResponse, GetCriticalAlertsData, GetCriticalAlertsResponse, AcknowledgeCriticalAlertData, AcknowledgeCriticalAlertResponse, AcknowledgeAllCriticalAlertsResponse, TestLicenseKeyData, TestLicenseKeyResponse, TestObjectStorageConfigData, TestObjectStorageConfigResponse, SendStatsResponse, GetLatestKeyRenewalAttemptResponse, RenewLicenseKeyData, RenewLicenseKeyResponse, CreateCustomerPortalSessionData, CreateCustomerPortalSessionResponse, TestMetadataData, TestMetadataResponse, ListGlobalSettingsResponse, GetCurrentEmailResponse, RefreshUserTokenData, RefreshUserTokenResponse, GetTutorialProgressResponse, UpdateTutorialProgressData, UpdateTutorialProgressResponse, LeaveInstanceResponse, GetUsageResponse, GetRunnableResponse, GlobalWhoamiResponse, ListWorkspaceInvitesResponse, WhoamiData, WhoamiResponse, GetGithubAppTokenData, GetGithubAppTokenResponse, InstallFromWorkspaceData, InstallFromWorkspaceResponse, DeleteFromWorkspaceData, DeleteFromWorkspaceResponse, ExportInstallationData, ExportInstallationResponse, ImportInstallationData, ImportInstallationResponse, AcceptInviteData, AcceptInviteResponse, DeclineInviteData, DeclineInviteResponse, InviteUserData, InviteUserResponse, AddUserData, AddUserResponse, DeleteInviteData, DeleteInviteResponse, ArchiveWorkspaceData, ArchiveWorkspaceResponse, UnarchiveWorkspaceData, UnarchiveWorkspaceResponse, DeleteWorkspaceData, DeleteWorkspaceResponse, LeaveWorkspaceData, LeaveWorkspaceResponse, GetWorkspaceNameData, GetWorkspaceNameResponse, ChangeWorkspaceNameData, ChangeWorkspaceNameResponse, ChangeWorkspaceIdData, ChangeWorkspaceIdResponse, ChangeWorkspaceColorData, ChangeWorkspaceColorResponse, WhoisData, WhoisResponse, UpdateOperatorSettingsData, UpdateOperatorSettingsResponse, ExistsEmailData, ExistsEmailResponse, ListUsersAsSuperAdminData, ListUsersAsSuperAdminResponse, ListPendingInvitesData, ListPendingInvitesResponse, GetSettingsData, GetSettingsResponse, GetDeployToData, GetDeployToResponse, GetIsPremiumData, GetIsPremiumResponse, GetPremiumInfoData, GetPremiumInfoResponse, GetThresholdAlertData, GetThresholdAlertResponse, SetThresholdAlertData, SetThresholdAlertResponse, EditSlackCommandData, EditSlackCommandResponse, EditTeamsCommandData, EditTeamsCommandResponse, ListAvailableTeamsIdsData, ListAvailableTeamsIdsResponse, ListAvailableTeamsChannelsData, ListAvailableTeamsChannelsResponse, ConnectTeamsData, ConnectTeamsResponse, RunSlackMessageTestJobData, RunSlackMessageTestJobResponse, RunTeamsMessageTestJobData, RunTeamsMessageTestJobResponse, EditDeployToData, EditDeployToResponse, EditAutoInviteData, EditAutoInviteResponse, EditWebhookData, EditWebhookResponse, EditCopilotConfigData, EditCopilotConfigResponse, GetCopilotInfoData, GetCopilotInfoResponse, EditErrorHandlerData, EditErrorHandlerResponse, EditLargeFileStorageConfigData, EditLargeFileStorageConfigResponse, EditWorkspaceGitSyncConfigData, EditWorkspaceGitSyncConfigResponse, EditWorkspaceDeployUiSettingsData, EditWorkspaceDeployUiSettingsResponse, EditWorkspaceDefaultAppData, EditWorkspaceDefaultAppResponse, EditDefaultScriptsData, EditDefaultScriptsResponse, GetDefaultScriptsData, GetDefaultScriptsResponse, SetEnvironmentVariableData, SetEnvironmentVariableResponse, GetWorkspaceEncryptionKeyData, GetWorkspaceEncryptionKeyResponse, SetWorkspaceEncryptionKeyData, SetWorkspaceEncryptionKeyResponse, GetWorkspaceDefaultAppData, GetWorkspaceDefaultAppResponse, GetLargeFileStorageConfigData, GetLargeFileStorageConfigResponse, GetWorkspaceUsageData, GetWorkspaceUsageResponse, GetUsedTriggersData, GetUsedTriggersResponse, ListUsersData, ListUsersResponse, ListUsersUsageData, ListUsersUsageResponse, ListUsernamesData, ListUsernamesResponse, UsernameToEmailData, UsernameToEmailResponse, CreateTokenData, CreateTokenResponse, CreateTokenImpersonateData, CreateTokenImpersonateResponse, DeleteTokenData, DeleteTokenResponse, ListTokensData, ListTokensResponse, GetOidcTokenData, GetOidcTokenResponse, CreateVariableData, CreateVariableResponse, EncryptValueData, EncryptValueResponse, DeleteVariableData, DeleteVariableResponse, UpdateVariableData, UpdateVariableResponse, GetVariableData, GetVariableResponse, GetVariableValueData, GetVariableValueResponse, ExistsVariableData, ExistsVariableResponse, ListVariableData, ListVariableResponse, ListContextualVariablesData, ListContextualVariablesResponse, WorkspaceGetCriticalAlertsData, WorkspaceGetCriticalAlertsResponse, WorkspaceAcknowledgeCriticalAlertData, WorkspaceAcknowledgeCriticalAlertResponse, WorkspaceAcknowledgeAllCriticalAlertsData, WorkspaceAcknowledgeAllCriticalAlertsResponse, WorkspaceMuteCriticalAlertsUiData, WorkspaceMuteCriticalAlertsUiResponse, LoginWithOauthData, LoginWithOauthResponse, ConnectSlackCallbackData, ConnectSlackCallbackResponse, ConnectSlackCallbackInstanceData, ConnectSlackCallbackInstanceResponse, ConnectCallbackData, ConnectCallbackResponse, CreateAccountData, CreateAccountResponse, RefreshTokenData, RefreshTokenResponse, DisconnectAccountData, DisconnectAccountResponse, DisconnectSlackData, DisconnectSlackResponse, DisconnectTeamsData, DisconnectTeamsResponse, ListOauthLoginsResponse, ListOauthConnectsResponse, GetOauthConnectData, GetOauthConnectResponse, SyncTeamsResponse, SendMessageToConversationData, SendMessageToConversationResponse, CreateResourceData, CreateResourceResponse, DeleteResourceData, DeleteResourceResponse, UpdateResourceData, UpdateResourceResponse, UpdateResourceValueData, UpdateResourceValueResponse, GetResourceData, GetResourceResponse, GetResourceValueInterpolatedData, GetResourceValueInterpolatedResponse, GetResourceValueData, GetResourceValueResponse, ExistsResourceData, ExistsResourceResponse, ListResourceData, ListResourceResponse, ListSearchResourceData, ListSearchResourceResponse, ListResourceNamesData, ListResourceNamesResponse, CreateResourceTypeData, CreateResourceTypeResponse, FileResourceTypeToFileExtMapData, FileResourceTypeToFileExtMapResponse, DeleteResourceTypeData, DeleteResourceTypeResponse, UpdateResourceTypeData, UpdateResourceTypeResponse, GetResourceTypeData, GetResourceTypeResponse, ExistsResourceTypeData, ExistsResourceTypeResponse, ListResourceTypeData, ListResourceTypeResponse, ListResourceTypeNamesData, ListResourceTypeNamesResponse, QueryResourceTypesData, QueryResourceTypesResponse, ListHubIntegrationsData, ListHubIntegrationsResponse, ListHubFlowsResponse, GetHubFlowByIdData, GetHubFlowByIdResponse, ListHubAppsResponse, GetHubAppByIdData, GetHubAppByIdResponse, GetPublicAppByCustomPathData, GetPublicAppByCustomPathResponse, GetHubScriptContentByPathData, GetHubScriptContentByPathResponse, GetHubScriptByPathData, GetHubScriptByPathResponse, GetTopHubScriptsData, GetTopHubScriptsResponse, QueryHubScriptsData, QueryHubScriptsResponse, ListSearchScriptData, ListSearchScriptResponse, ListScriptsData, ListScriptsResponse, ListScriptPathsData, ListScriptPathsResponse, CreateDraftData, CreateDraftResponse, DeleteDraftData, DeleteDraftResponse, CreateScriptData, CreateScriptResponse, ToggleWorkspaceErrorHandlerForScriptData, ToggleWorkspaceErrorHandlerForScriptResponse, GetCustomTagsData, GetCustomTagsResponse, GeDefaultTagsResponse, IsDefaultTagsPerWorkspaceResponse, ArchiveScriptByPathData, ArchiveScriptByPathResponse, ArchiveScriptByHashData, ArchiveScriptByHashResponse, DeleteScriptByHashData, DeleteScriptByHashResponse, DeleteScriptByPathData, DeleteScriptByPathResponse, GetScriptByPathData, GetScriptByPathResponse, GetTriggersCountOfScriptData, GetTriggersCountOfScriptResponse, ListTokensOfScriptData, ListTokensOfScriptResponse, GetScriptByPathWithDraftData, GetScriptByPathWithDraftResponse, GetScriptHistoryByPathData, GetScriptHistoryByPathResponse, ListScriptPathsFromWorkspaceRunnableData, ListScriptPathsFromWorkspaceRunnableResponse, GetScriptLatestVersionData, GetScriptLatestVersionResponse, UpdateScriptHistoryData, UpdateScriptHistoryResponse, RawScriptByPathData, RawScriptByPathResponse, RawScriptByPathTokenedData, RawScriptByPathTokenedResponse, ExistsScriptByPathData, ExistsScriptByPathResponse, GetScriptByHashData, GetScriptByHashResponse, RawScriptByHashData, RawScriptByHashResponse, GetScriptDeploymentStatusData, GetScriptDeploymentStatusResponse, RunScriptByPathData, RunScriptByPathResponse, OpenaiSyncScriptByPathData, OpenaiSyncScriptByPathResponse, RunWaitResultScriptByPathData, RunWaitResultScriptByPathResponse, RunWaitResultScriptByPathGetData, RunWaitResultScriptByPathGetResponse, OpenaiSyncFlowByPathData, OpenaiSyncFlowByPathResponse, RunWaitResultFlowByPathData, RunWaitResultFlowByPathResponse, ResultByIdData, ResultByIdResponse, ListFlowPathsData, ListFlowPathsResponse, ListSearchFlowData, ListSearchFlowResponse, ListFlowsData, ListFlowsResponse, GetFlowHistoryData, GetFlowHistoryResponse, GetFlowLatestVersionData, GetFlowLatestVersionResponse, ListFlowPathsFromWorkspaceRunnableData, ListFlowPathsFromWorkspaceRunnableResponse, GetFlowVersionData, GetFlowVersionResponse, UpdateFlowHistoryData, UpdateFlowHistoryResponse, GetFlowByPathData, GetFlowByPathResponse, GetFlowDeploymentStatusData, GetFlowDeploymentStatusResponse, GetTriggersCountOfFlowData, GetTriggersCountOfFlowResponse, ListTokensOfFlowData, ListTokensOfFlowResponse, ToggleWorkspaceErrorHandlerForFlowData, ToggleWorkspaceErrorHandlerForFlowResponse, GetFlowByPathWithDraftData, GetFlowByPathWithDraftResponse, ExistsFlowByPathData, ExistsFlowByPathResponse, CreateFlowData, CreateFlowResponse, UpdateFlowData, UpdateFlowResponse, ArchiveFlowByPathData, ArchiveFlowByPathResponse, DeleteFlowByPathData, DeleteFlowByPathResponse, ListRawAppsData, ListRawAppsResponse, ExistsRawAppData, ExistsRawAppResponse, GetRawAppDataData, GetRawAppDataResponse, ListSearchAppData, ListSearchAppResponse, ListAppsData, ListAppsResponse, CreateAppData, CreateAppResponse, ExistsAppData, ExistsAppResponse, GetAppByPathData, GetAppByPathResponse, GetAppLiteByPathData, GetAppLiteByPathResponse, GetAppByPathWithDraftData, GetAppByPathWithDraftResponse, GetAppHistoryByPathData, GetAppHistoryByPathResponse, GetAppLatestVersionData, GetAppLatestVersionResponse, ListAppPathsFromWorkspaceRunnableData, ListAppPathsFromWorkspaceRunnableResponse, UpdateAppHistoryData, UpdateAppHistoryResponse, GetPublicAppBySecretData, GetPublicAppBySecretResponse, GetPublicResourceData, GetPublicResourceResponse, GetPublicSecretOfAppData, GetPublicSecretOfAppResponse, GetAppByVersionData, GetAppByVersionResponse, CreateRawAppData, CreateRawAppResponse, UpdateRawAppData, UpdateRawAppResponse, DeleteRawAppData, DeleteRawAppResponse, DeleteAppData, DeleteAppResponse, UpdateAppData, UpdateAppResponse, CustomPathExistsData, CustomPathExistsResponse, ExecuteComponentData, ExecuteComponentResponse, UploadS3FileFromAppData, UploadS3FileFromAppResponse, DeleteS3FileFromAppData, DeleteS3FileFromAppResponse, RunFlowByPathData, RunFlowByPathResponse, RestartFlowAtStepData, RestartFlowAtStepResponse, RunScriptByHashData, RunScriptByHashResponse, RunScriptPreviewData, RunScriptPreviewResponse, RunCodeWorkflowTaskData, RunCodeWorkflowTaskResponse, RunRawScriptDependenciesData, RunRawScriptDependenciesResponse, RunFlowPreviewData, RunFlowPreviewResponse, ListQueueData, ListQueueResponse, GetQueueCountData, GetQueueCountResponse, GetCompletedCountData, GetCompletedCountResponse, CountCompletedJobsData, CountCompletedJobsResponse, ListFilteredUuidsData, ListFilteredUuidsResponse, CancelSelectionData, CancelSelectionResponse, ListCompletedJobsData, ListCompletedJobsResponse, ListJobsData, ListJobsResponse, GetDbClockResponse, CountJobsByTagData, CountJobsByTagResponse, GetJobData, GetJobResponse, GetRootJobIdData, GetRootJobIdResponse, GetJobLogsData, GetJobLogsResponse, GetJobArgsData, GetJobArgsResponse, GetJobUpdatesData, GetJobUpdatesResponse, GetLogFileFromStoreData, GetLogFileFromStoreResponse, GetFlowDebugInfoData, GetFlowDebugInfoResponse, GetCompletedJobData, GetCompletedJobResponse, GetCompletedJobResultData, GetCompletedJobResultResponse, GetCompletedJobResultMaybeData, GetCompletedJobResultMaybeResponse, DeleteCompletedJobData, DeleteCompletedJobResponse, CancelQueuedJobData, CancelQueuedJobResponse, CancelPersistentQueuedJobsData, CancelPersistentQueuedJobsResponse, ForceCancelQueuedJobData, ForceCancelQueuedJobResponse, CreateJobSignatureData, CreateJobSignatureResponse, GetResumeUrlsData, GetResumeUrlsResponse, GetSlackApprovalPayloadData, GetSlackApprovalPayloadResponse, ResumeSuspendedJobGetData, ResumeSuspendedJobGetResponse, ResumeSuspendedJobPostData, ResumeSuspendedJobPostResponse, SetFlowUserStateData, SetFlowUserStateResponse, GetFlowUserStateData, GetFlowUserStateResponse, ResumeSuspendedFlowAsOwnerData, ResumeSuspendedFlowAsOwnerResponse, CancelSuspendedJobGetData, CancelSuspendedJobGetResponse, CancelSuspendedJobPostData, CancelSuspendedJobPostResponse, GetSuspendedJobFlowData, GetSuspendedJobFlowResponse, PreviewScheduleData, PreviewScheduleResponse, CreateScheduleData, CreateScheduleResponse, UpdateScheduleData, UpdateScheduleResponse, SetScheduleEnabledData, SetScheduleEnabledResponse, DeleteScheduleData, DeleteScheduleResponse, GetScheduleData, GetScheduleResponse, ExistsScheduleData, ExistsScheduleResponse, ListSchedulesData, ListSchedulesResponse, ListSchedulesWithJobsData, ListSchedulesWithJobsResponse, SetDefaultErrorOrRecoveryHandlerData, SetDefaultErrorOrRecoveryHandlerResponse, CreateHttpTriggerData, CreateHttpTriggerResponse, UpdateHttpTriggerData, UpdateHttpTriggerResponse, DeleteHttpTriggerData, DeleteHttpTriggerResponse, GetHttpTriggerData, GetHttpTriggerResponse, ListHttpTriggersData, ListHttpTriggersResponse, ExistsHttpTriggerData, ExistsHttpTriggerResponse, ExistsRouteData, ExistsRouteResponse, CreateWebsocketTriggerData, CreateWebsocketTriggerResponse, UpdateWebsocketTriggerData, UpdateWebsocketTriggerResponse, DeleteWebsocketTriggerData, DeleteWebsocketTriggerResponse, GetWebsocketTriggerData, GetWebsocketTriggerResponse, ListWebsocketTriggersData, ListWebsocketTriggersResponse, ExistsWebsocketTriggerData, ExistsWebsocketTriggerResponse, SetWebsocketTriggerEnabledData, SetWebsocketTriggerEnabledResponse, TestWebsocketConnectionData, TestWebsocketConnectionResponse, CreateKafkaTriggerData, CreateKafkaTriggerResponse, UpdateKafkaTriggerData, UpdateKafkaTriggerResponse, DeleteKafkaTriggerData, DeleteKafkaTriggerResponse, GetKafkaTriggerData, GetKafkaTriggerResponse, ListKafkaTriggersData, ListKafkaTriggersResponse, ExistsKafkaTriggerData, ExistsKafkaTriggerResponse, SetKafkaTriggerEnabledData, SetKafkaTriggerEnabledResponse, TestKafkaConnectionData, TestKafkaConnectionResponse, CreateNatsTriggerData, CreateNatsTriggerResponse, UpdateNatsTriggerData, UpdateNatsTriggerResponse, DeleteNatsTriggerData, DeleteNatsTriggerResponse, GetNatsTriggerData, GetNatsTriggerResponse, ListNatsTriggersData, ListNatsTriggersResponse, ExistsNatsTriggerData, ExistsNatsTriggerResponse, SetNatsTriggerEnabledData, SetNatsTriggerEnabledResponse, TestNatsConnectionData, TestNatsConnectionResponse, CreateSqsTriggerData, CreateSqsTriggerResponse, UpdateSqsTriggerData, UpdateSqsTriggerResponse, DeleteSqsTriggerData, DeleteSqsTriggerResponse, GetSqsTriggerData, GetSqsTriggerResponse, ListSqsTriggersData, ListSqsTriggersResponse, ExistsSqsTriggerData, ExistsSqsTriggerResponse, SetSqsTriggerEnabledData, SetSqsTriggerEnabledResponse, TestSqsConnectionData, TestSqsConnectionResponse, CreateMqttTriggerData, CreateMqttTriggerResponse, UpdateMqttTriggerData, UpdateMqttTriggerResponse, DeleteMqttTriggerData, DeleteMqttTriggerResponse, GetMqttTriggerData, GetMqttTriggerResponse, ListMqttTriggersData, ListMqttTriggersResponse, ExistsMqttTriggerData, ExistsMqttTriggerResponse, SetMqttTriggerEnabledData, SetMqttTriggerEnabledResponse, TestMqttConnectionData, TestMqttConnectionResponse, IsValidPostgresConfigurationData, IsValidPostgresConfigurationResponse, CreateTemplateScriptData, CreateTemplateScriptResponse, GetTemplateScriptData, GetTemplateScriptResponse, ListPostgresReplicationSlotData, ListPostgresReplicationSlotResponse, CreatePostgresReplicationSlotData, CreatePostgresReplicationSlotResponse, DeletePostgresReplicationSlotData, DeletePostgresReplicationSlotResponse, ListPostgresPublicationData, ListPostgresPublicationResponse, GetPostgresPublicationData, GetPostgresPublicationResponse, CreatePostgresPublicationData, CreatePostgresPublicationResponse, UpdatePostgresPublicationData, UpdatePostgresPublicationResponse, DeletePostgresPublicationData, DeletePostgresPublicationResponse, CreatePostgresTriggerData, CreatePostgresTriggerResponse, UpdatePostgresTriggerData, UpdatePostgresTriggerResponse, DeletePostgresTriggerData, DeletePostgresTriggerResponse, GetPostgresTriggerData, GetPostgresTriggerResponse, ListPostgresTriggersData, ListPostgresTriggersResponse, ExistsPostgresTriggerData, ExistsPostgresTriggerResponse, SetPostgresTriggerEnabledData, SetPostgresTriggerEnabledResponse, TestPostgresConnectionData, TestPostgresConnectionResponse, ListInstanceGroupsResponse, GetInstanceGroupData, GetInstanceGroupResponse, CreateInstanceGroupData, CreateInstanceGroupResponse, UpdateInstanceGroupData, UpdateInstanceGroupResponse, DeleteInstanceGroupData, DeleteInstanceGroupResponse, AddUserToInstanceGroupData, AddUserToInstanceGroupResponse, RemoveUserFromInstanceGroupData, RemoveUserFromInstanceGroupResponse, ExportInstanceGroupsResponse, OverwriteInstanceGroupsData, OverwriteInstanceGroupsResponse, ListGroupsData, ListGroupsResponse, ListGroupNamesData, ListGroupNamesResponse, CreateGroupData, CreateGroupResponse, UpdateGroupData, UpdateGroupResponse, DeleteGroupData, DeleteGroupResponse, GetGroupData, GetGroupResponse, AddUserToGroupData, AddUserToGroupResponse, RemoveUserToGroupData, RemoveUserToGroupResponse, ListFoldersData, ListFoldersResponse, ListFolderNamesData, ListFolderNamesResponse, CreateFolderData, CreateFolderResponse, UpdateFolderData, UpdateFolderResponse, DeleteFolderData, DeleteFolderResponse, GetFolderData, GetFolderResponse, ExistsFolderData, ExistsFolderResponse, GetFolderUsageData, GetFolderUsageResponse, AddOwnerToFolderData, AddOwnerToFolderResponse, RemoveOwnerToFolderData, RemoveOwnerToFolderResponse, ListWorkersData, ListWorkersResponse, ExistsWorkerWithTagData, ExistsWorkerWithTagResponse, GetQueueMetricsResponse, GetCountsOfJobsWaitingPerTagResponse, ListWorkerGroupsResponse, GetConfigData, GetConfigResponse, UpdateConfigData, UpdateConfigResponse, DeleteConfigData, DeleteConfigResponse, ListConfigsResponse, ListAutoscalingEventsData, ListAutoscalingEventsResponse, GetGranularAclsData, GetGranularAclsResponse, AddGranularAclsData, AddGranularAclsResponse, RemoveGranularAclsData, RemoveGranularAclsResponse, SetCaptureConfigData, SetCaptureConfigResponse, PingCaptureConfigData, PingCaptureConfigResponse, GetCaptureConfigsData, GetCaptureConfigsResponse, ListCapturesData, ListCapturesResponse, MoveCapturesAndConfigsData, MoveCapturesAndConfigsResponse, GetCaptureData, GetCaptureResponse, DeleteCaptureData, DeleteCaptureResponse, StarData, StarResponse, UnstarData, UnstarResponse, GetInputHistoryData, GetInputHistoryResponse, GetArgsFromHistoryOrSavedInputData, GetArgsFromHistoryOrSavedInputResponse, ListInputsData, ListInputsResponse, CreateInputData, CreateInputResponse, UpdateInputData, UpdateInputResponse, DeleteInputData, DeleteInputResponse, DuckdbConnectionSettingsData, DuckdbConnectionSettingsResponse, DuckdbConnectionSettingsV2Data, DuckdbConnectionSettingsV2Response, PolarsConnectionSettingsData, PolarsConnectionSettingsResponse, PolarsConnectionSettingsV2Data, PolarsConnectionSettingsV2Response, S3ResourceInfoData, S3ResourceInfoResponse, DatasetStorageTestConnectionData, DatasetStorageTestConnectionResponse, ListStoredFilesData, ListStoredFilesResponse, LoadFileMetadataData, LoadFileMetadataResponse, LoadFilePreviewData, LoadFilePreviewResponse, LoadParquetPreviewData, LoadParquetPreviewResponse, LoadTableRowCountData, LoadTableRowCountResponse, LoadCsvPreviewData, LoadCsvPreviewResponse, DeleteS3FileData, DeleteS3FileResponse, MoveS3FileData, MoveS3FileResponse, FileUploadData, FileUploadResponse, FileDownloadData, FileDownloadResponse, FileDownloadParquetAsCsvData, FileDownloadParquetAsCsvResponse, GetJobMetricsData, GetJobMetricsResponse, SetJobProgressData, SetJobProgressResponse, GetJobProgressData, GetJobProgressResponse, ListLogFilesData, ListLogFilesResponse, GetLogFileData, GetLogFileResponse, ListConcurrencyGroupsResponse, DeleteConcurrencyGroupData, DeleteConcurrencyGroupResponse, GetConcurrencyKeyData, GetConcurrencyKeyResponse, ListExtendedJobsData, ListExtendedJobsResponse, SearchJobsIndexData, SearchJobsIndexResponse, SearchLogsIndexData, SearchLogsIndexResponse, CountSearchLogsIndexData, CountSearchLogsIndexResponse, ClearIndexData, ClearIndexResponse } from './types.gen.ts'; +import type { BackendVersionResponse, BackendUptodateResponse, GetLicenseIdResponse, GetOpenApiYamlResponse, GetAuditLogData, GetAuditLogResponse, ListAuditLogsData, ListAuditLogsResponse, LoginData, LoginResponse, LogoutResponse, GetUserData, GetUserResponse, UpdateUserData, UpdateUserResponse, IsOwnerOfPathData, IsOwnerOfPathResponse, SetPasswordData, SetPasswordResponse, SetPasswordForUserData, SetPasswordForUserResponse, SetLoginTypeForUserData, SetLoginTypeForUserResponse, CreateUserGloballyData, CreateUserGloballyResponse, GlobalUserUpdateData, GlobalUserUpdateResponse, GlobalUsernameInfoData, GlobalUsernameInfoResponse, GlobalUserRenameData, GlobalUserRenameResponse, GlobalUserDeleteData, GlobalUserDeleteResponse, GlobalUsersOverwriteData, GlobalUsersOverwriteResponse, GlobalUsersExportResponse, DeleteUserData, DeleteUserResponse, GetGlobalConnectedRepositoriesResponse, ListWorkspacesResponse, IsDomainAllowedResponse, ListUserWorkspacesResponse, ListWorkspacesAsSuperAdminData, ListWorkspacesAsSuperAdminResponse, CreateWorkspaceData, CreateWorkspaceResponse, ExistsWorkspaceData, ExistsWorkspaceResponse, ExistsUsernameData, ExistsUsernameResponse, GetGlobalData, GetGlobalResponse, SetGlobalData, SetGlobalResponse, GetLocalResponse, TestSmtpData, TestSmtpResponse, TestCriticalChannelsData, TestCriticalChannelsResponse, GetCriticalAlertsData, GetCriticalAlertsResponse, AcknowledgeCriticalAlertData, AcknowledgeCriticalAlertResponse, AcknowledgeAllCriticalAlertsResponse, TestLicenseKeyData, TestLicenseKeyResponse, TestObjectStorageConfigData, TestObjectStorageConfigResponse, SendStatsResponse, GetLatestKeyRenewalAttemptResponse, RenewLicenseKeyData, RenewLicenseKeyResponse, CreateCustomerPortalSessionData, CreateCustomerPortalSessionResponse, TestMetadataData, TestMetadataResponse, ListGlobalSettingsResponse, GetCurrentEmailResponse, RefreshUserTokenData, RefreshUserTokenResponse, GetTutorialProgressResponse, UpdateTutorialProgressData, UpdateTutorialProgressResponse, LeaveInstanceResponse, GetUsageResponse, GetRunnableResponse, GlobalWhoamiResponse, ListWorkspaceInvitesResponse, WhoamiData, WhoamiResponse, GetGithubAppTokenData, GetGithubAppTokenResponse, InstallFromWorkspaceData, InstallFromWorkspaceResponse, DeleteFromWorkspaceData, DeleteFromWorkspaceResponse, ExportInstallationData, ExportInstallationResponse, ImportInstallationData, ImportInstallationResponse, AcceptInviteData, AcceptInviteResponse, DeclineInviteData, DeclineInviteResponse, InviteUserData, InviteUserResponse, AddUserData, AddUserResponse, DeleteInviteData, DeleteInviteResponse, ArchiveWorkspaceData, ArchiveWorkspaceResponse, UnarchiveWorkspaceData, UnarchiveWorkspaceResponse, DeleteWorkspaceData, DeleteWorkspaceResponse, LeaveWorkspaceData, LeaveWorkspaceResponse, GetWorkspaceNameData, GetWorkspaceNameResponse, ChangeWorkspaceNameData, ChangeWorkspaceNameResponse, ChangeWorkspaceIdData, ChangeWorkspaceIdResponse, ChangeWorkspaceColorData, ChangeWorkspaceColorResponse, WhoisData, WhoisResponse, UpdateOperatorSettingsData, UpdateOperatorSettingsResponse, ExistsEmailData, ExistsEmailResponse, ListUsersAsSuperAdminData, ListUsersAsSuperAdminResponse, ListPendingInvitesData, ListPendingInvitesResponse, GetSettingsData, GetSettingsResponse, GetDeployToData, GetDeployToResponse, GetIsPremiumData, GetIsPremiumResponse, GetPremiumInfoData, GetPremiumInfoResponse, GetThresholdAlertData, GetThresholdAlertResponse, SetThresholdAlertData, SetThresholdAlertResponse, EditSlackCommandData, EditSlackCommandResponse, EditTeamsCommandData, EditTeamsCommandResponse, ListAvailableTeamsIdsData, ListAvailableTeamsIdsResponse, ListAvailableTeamsChannelsData, ListAvailableTeamsChannelsResponse, ConnectTeamsData, ConnectTeamsResponse, RunSlackMessageTestJobData, RunSlackMessageTestJobResponse, RunTeamsMessageTestJobData, RunTeamsMessageTestJobResponse, EditDeployToData, EditDeployToResponse, EditAutoInviteData, EditAutoInviteResponse, EditWebhookData, EditWebhookResponse, EditCopilotConfigData, EditCopilotConfigResponse, GetCopilotInfoData, GetCopilotInfoResponse, EditErrorHandlerData, EditErrorHandlerResponse, EditLargeFileStorageConfigData, EditLargeFileStorageConfigResponse, EditWorkspaceGitSyncConfigData, EditWorkspaceGitSyncConfigResponse, EditWorkspaceDeployUiSettingsData, EditWorkspaceDeployUiSettingsResponse, EditWorkspaceDefaultAppData, EditWorkspaceDefaultAppResponse, EditDefaultScriptsData, EditDefaultScriptsResponse, GetDefaultScriptsData, GetDefaultScriptsResponse, SetEnvironmentVariableData, SetEnvironmentVariableResponse, GetWorkspaceEncryptionKeyData, GetWorkspaceEncryptionKeyResponse, SetWorkspaceEncryptionKeyData, SetWorkspaceEncryptionKeyResponse, GetWorkspaceDefaultAppData, GetWorkspaceDefaultAppResponse, GetLargeFileStorageConfigData, GetLargeFileStorageConfigResponse, GetWorkspaceUsageData, GetWorkspaceUsageResponse, GetUsedTriggersData, GetUsedTriggersResponse, ListUsersData, ListUsersResponse, ListUsersUsageData, ListUsersUsageResponse, ListUsernamesData, ListUsernamesResponse, UsernameToEmailData, UsernameToEmailResponse, CreateTokenData, CreateTokenResponse, CreateTokenImpersonateData, CreateTokenImpersonateResponse, DeleteTokenData, DeleteTokenResponse, ListTokensData, ListTokensResponse, GetOidcTokenData, GetOidcTokenResponse, CreateVariableData, CreateVariableResponse, EncryptValueData, EncryptValueResponse, DeleteVariableData, DeleteVariableResponse, UpdateVariableData, UpdateVariableResponse, GetVariableData, GetVariableResponse, GetVariableValueData, GetVariableValueResponse, ExistsVariableData, ExistsVariableResponse, ListVariableData, ListVariableResponse, ListContextualVariablesData, ListContextualVariablesResponse, WorkspaceGetCriticalAlertsData, WorkspaceGetCriticalAlertsResponse, WorkspaceAcknowledgeCriticalAlertData, WorkspaceAcknowledgeCriticalAlertResponse, WorkspaceAcknowledgeAllCriticalAlertsData, WorkspaceAcknowledgeAllCriticalAlertsResponse, WorkspaceMuteCriticalAlertsUiData, WorkspaceMuteCriticalAlertsUiResponse, LoginWithOauthData, LoginWithOauthResponse, ConnectSlackCallbackData, ConnectSlackCallbackResponse, ConnectSlackCallbackInstanceData, ConnectSlackCallbackInstanceResponse, ConnectCallbackData, ConnectCallbackResponse, CreateAccountData, CreateAccountResponse, RefreshTokenData, RefreshTokenResponse, DisconnectAccountData, DisconnectAccountResponse, DisconnectSlackData, DisconnectSlackResponse, DisconnectTeamsData, DisconnectTeamsResponse, ListOauthLoginsResponse, ListOauthConnectsResponse, GetOauthConnectData, GetOauthConnectResponse, SyncTeamsResponse, SendMessageToConversationData, SendMessageToConversationResponse, CreateResourceData, CreateResourceResponse, DeleteResourceData, DeleteResourceResponse, UpdateResourceData, UpdateResourceResponse, UpdateResourceValueData, UpdateResourceValueResponse, GetResourceData, GetResourceResponse, GetResourceValueInterpolatedData, GetResourceValueInterpolatedResponse, GetResourceValueData, GetResourceValueResponse, ExistsResourceData, ExistsResourceResponse, ListResourceData, ListResourceResponse, ListSearchResourceData, ListSearchResourceResponse, ListResourceNamesData, ListResourceNamesResponse, CreateResourceTypeData, CreateResourceTypeResponse, FileResourceTypeToFileExtMapData, FileResourceTypeToFileExtMapResponse, DeleteResourceTypeData, DeleteResourceTypeResponse, UpdateResourceTypeData, UpdateResourceTypeResponse, GetResourceTypeData, GetResourceTypeResponse, ExistsResourceTypeData, ExistsResourceTypeResponse, ListResourceTypeData, ListResourceTypeResponse, ListResourceTypeNamesData, ListResourceTypeNamesResponse, QueryResourceTypesData, QueryResourceTypesResponse, ListHubIntegrationsData, ListHubIntegrationsResponse, ListHubFlowsResponse, GetHubFlowByIdData, GetHubFlowByIdResponse, ListHubAppsResponse, GetHubAppByIdData, GetHubAppByIdResponse, GetPublicAppByCustomPathData, GetPublicAppByCustomPathResponse, GetHubScriptContentByPathData, GetHubScriptContentByPathResponse, GetHubScriptByPathData, GetHubScriptByPathResponse, GetTopHubScriptsData, GetTopHubScriptsResponse, QueryHubScriptsData, QueryHubScriptsResponse, ListSearchScriptData, ListSearchScriptResponse, ListScriptsData, ListScriptsResponse, ListScriptPathsData, ListScriptPathsResponse, CreateDraftData, CreateDraftResponse, DeleteDraftData, DeleteDraftResponse, CreateScriptData, CreateScriptResponse, ToggleWorkspaceErrorHandlerForScriptData, ToggleWorkspaceErrorHandlerForScriptResponse, GetCustomTagsData, GetCustomTagsResponse, GeDefaultTagsResponse, IsDefaultTagsPerWorkspaceResponse, ArchiveScriptByPathData, ArchiveScriptByPathResponse, ArchiveScriptByHashData, ArchiveScriptByHashResponse, DeleteScriptByHashData, DeleteScriptByHashResponse, DeleteScriptByPathData, DeleteScriptByPathResponse, GetScriptByPathData, GetScriptByPathResponse, GetTriggersCountOfScriptData, GetTriggersCountOfScriptResponse, ListTokensOfScriptData, ListTokensOfScriptResponse, GetScriptByPathWithDraftData, GetScriptByPathWithDraftResponse, GetScriptHistoryByPathData, GetScriptHistoryByPathResponse, ListScriptPathsFromWorkspaceRunnableData, ListScriptPathsFromWorkspaceRunnableResponse, GetScriptLatestVersionData, GetScriptLatestVersionResponse, UpdateScriptHistoryData, UpdateScriptHistoryResponse, RawScriptByPathData, RawScriptByPathResponse, RawScriptByPathTokenedData, RawScriptByPathTokenedResponse, ExistsScriptByPathData, ExistsScriptByPathResponse, GetScriptByHashData, GetScriptByHashResponse, RawScriptByHashData, RawScriptByHashResponse, GetScriptDeploymentStatusData, GetScriptDeploymentStatusResponse, RunScriptByPathData, RunScriptByPathResponse, OpenaiSyncScriptByPathData, OpenaiSyncScriptByPathResponse, RunWaitResultScriptByPathData, RunWaitResultScriptByPathResponse, RunWaitResultScriptByPathGetData, RunWaitResultScriptByPathGetResponse, OpenaiSyncFlowByPathData, OpenaiSyncFlowByPathResponse, RunWaitResultFlowByPathData, RunWaitResultFlowByPathResponse, ResultByIdData, ResultByIdResponse, ListFlowPathsData, ListFlowPathsResponse, ListSearchFlowData, ListSearchFlowResponse, ListFlowsData, ListFlowsResponse, GetFlowHistoryData, GetFlowHistoryResponse, GetFlowLatestVersionData, GetFlowLatestVersionResponse, ListFlowPathsFromWorkspaceRunnableData, ListFlowPathsFromWorkspaceRunnableResponse, GetFlowVersionData, GetFlowVersionResponse, UpdateFlowHistoryData, UpdateFlowHistoryResponse, GetFlowByPathData, GetFlowByPathResponse, GetFlowDeploymentStatusData, GetFlowDeploymentStatusResponse, GetTriggersCountOfFlowData, GetTriggersCountOfFlowResponse, ListTokensOfFlowData, ListTokensOfFlowResponse, ToggleWorkspaceErrorHandlerForFlowData, ToggleWorkspaceErrorHandlerForFlowResponse, GetFlowByPathWithDraftData, GetFlowByPathWithDraftResponse, ExistsFlowByPathData, ExistsFlowByPathResponse, CreateFlowData, CreateFlowResponse, UpdateFlowData, UpdateFlowResponse, ArchiveFlowByPathData, ArchiveFlowByPathResponse, DeleteFlowByPathData, DeleteFlowByPathResponse, ListRawAppsData, ListRawAppsResponse, ExistsRawAppData, ExistsRawAppResponse, GetRawAppDataData, GetRawAppDataResponse, ListSearchAppData, ListSearchAppResponse, ListAppsData, ListAppsResponse, CreateAppData, CreateAppResponse, ExistsAppData, ExistsAppResponse, GetAppByPathData, GetAppByPathResponse, GetAppLiteByPathData, GetAppLiteByPathResponse, GetAppByPathWithDraftData, GetAppByPathWithDraftResponse, GetAppHistoryByPathData, GetAppHistoryByPathResponse, GetAppLatestVersionData, GetAppLatestVersionResponse, ListAppPathsFromWorkspaceRunnableData, ListAppPathsFromWorkspaceRunnableResponse, UpdateAppHistoryData, UpdateAppHistoryResponse, GetPublicAppBySecretData, GetPublicAppBySecretResponse, GetPublicResourceData, GetPublicResourceResponse, GetPublicSecretOfAppData, GetPublicSecretOfAppResponse, GetAppByVersionData, GetAppByVersionResponse, CreateRawAppData, CreateRawAppResponse, UpdateRawAppData, UpdateRawAppResponse, DeleteRawAppData, DeleteRawAppResponse, DeleteAppData, DeleteAppResponse, UpdateAppData, UpdateAppResponse, CustomPathExistsData, CustomPathExistsResponse, ExecuteComponentData, ExecuteComponentResponse, UploadS3FileFromAppData, UploadS3FileFromAppResponse, DeleteS3FileFromAppData, DeleteS3FileFromAppResponse, RunFlowByPathData, RunFlowByPathResponse, RestartFlowAtStepData, RestartFlowAtStepResponse, RunScriptByHashData, RunScriptByHashResponse, RunScriptPreviewData, RunScriptPreviewResponse, RunCodeWorkflowTaskData, RunCodeWorkflowTaskResponse, RunRawScriptDependenciesData, RunRawScriptDependenciesResponse, RunFlowPreviewData, RunFlowPreviewResponse, ListQueueData, ListQueueResponse, GetQueueCountData, GetQueueCountResponse, GetCompletedCountData, GetCompletedCountResponse, CountCompletedJobsData, CountCompletedJobsResponse, ListFilteredUuidsData, ListFilteredUuidsResponse, CancelSelectionData, CancelSelectionResponse, ListCompletedJobsData, ListCompletedJobsResponse, ListJobsData, ListJobsResponse, GetDbClockResponse, CountJobsByTagData, CountJobsByTagResponse, GetJobData, GetJobResponse, GetRootJobIdData, GetRootJobIdResponse, GetJobLogsData, GetJobLogsResponse, GetJobArgsData, GetJobArgsResponse, GetJobUpdatesData, GetJobUpdatesResponse, GetLogFileFromStoreData, GetLogFileFromStoreResponse, GetFlowDebugInfoData, GetFlowDebugInfoResponse, GetCompletedJobData, GetCompletedJobResponse, GetCompletedJobResultData, GetCompletedJobResultResponse, GetCompletedJobResultMaybeData, GetCompletedJobResultMaybeResponse, DeleteCompletedJobData, DeleteCompletedJobResponse, CancelQueuedJobData, CancelQueuedJobResponse, CancelPersistentQueuedJobsData, CancelPersistentQueuedJobsResponse, ForceCancelQueuedJobData, ForceCancelQueuedJobResponse, CreateJobSignatureData, CreateJobSignatureResponse, GetResumeUrlsData, GetResumeUrlsResponse, GetSlackApprovalPayloadData, GetSlackApprovalPayloadResponse, ResumeSuspendedJobGetData, ResumeSuspendedJobGetResponse, ResumeSuspendedJobPostData, ResumeSuspendedJobPostResponse, SetFlowUserStateData, SetFlowUserStateResponse, GetFlowUserStateData, GetFlowUserStateResponse, ResumeSuspendedFlowAsOwnerData, ResumeSuspendedFlowAsOwnerResponse, CancelSuspendedJobGetData, CancelSuspendedJobGetResponse, CancelSuspendedJobPostData, CancelSuspendedJobPostResponse, GetSuspendedJobFlowData, GetSuspendedJobFlowResponse, PreviewScheduleData, PreviewScheduleResponse, CreateScheduleData, CreateScheduleResponse, UpdateScheduleData, UpdateScheduleResponse, SetScheduleEnabledData, SetScheduleEnabledResponse, DeleteScheduleData, DeleteScheduleResponse, GetScheduleData, GetScheduleResponse, ExistsScheduleData, ExistsScheduleResponse, ListSchedulesData, ListSchedulesResponse, ListSchedulesWithJobsData, ListSchedulesWithJobsResponse, SetDefaultErrorOrRecoveryHandlerData, SetDefaultErrorOrRecoveryHandlerResponse, CreateHttpTriggerData, CreateHttpTriggerResponse, UpdateHttpTriggerData, UpdateHttpTriggerResponse, DeleteHttpTriggerData, DeleteHttpTriggerResponse, GetHttpTriggerData, GetHttpTriggerResponse, ListHttpTriggersData, ListHttpTriggersResponse, ExistsHttpTriggerData, ExistsHttpTriggerResponse, ExistsRouteData, ExistsRouteResponse, CreateWebsocketTriggerData, CreateWebsocketTriggerResponse, UpdateWebsocketTriggerData, UpdateWebsocketTriggerResponse, DeleteWebsocketTriggerData, DeleteWebsocketTriggerResponse, GetWebsocketTriggerData, GetWebsocketTriggerResponse, ListWebsocketTriggersData, ListWebsocketTriggersResponse, ExistsWebsocketTriggerData, ExistsWebsocketTriggerResponse, SetWebsocketTriggerEnabledData, SetWebsocketTriggerEnabledResponse, TestWebsocketConnectionData, TestWebsocketConnectionResponse, CreateKafkaTriggerData, CreateKafkaTriggerResponse, UpdateKafkaTriggerData, UpdateKafkaTriggerResponse, DeleteKafkaTriggerData, DeleteKafkaTriggerResponse, GetKafkaTriggerData, GetKafkaTriggerResponse, ListKafkaTriggersData, ListKafkaTriggersResponse, ExistsKafkaTriggerData, ExistsKafkaTriggerResponse, SetKafkaTriggerEnabledData, SetKafkaTriggerEnabledResponse, TestKafkaConnectionData, TestKafkaConnectionResponse, CreateNatsTriggerData, CreateNatsTriggerResponse, UpdateNatsTriggerData, UpdateNatsTriggerResponse, DeleteNatsTriggerData, DeleteNatsTriggerResponse, GetNatsTriggerData, GetNatsTriggerResponse, ListNatsTriggersData, ListNatsTriggersResponse, ExistsNatsTriggerData, ExistsNatsTriggerResponse, SetNatsTriggerEnabledData, SetNatsTriggerEnabledResponse, TestNatsConnectionData, TestNatsConnectionResponse, CreateSqsTriggerData, CreateSqsTriggerResponse, UpdateSqsTriggerData, UpdateSqsTriggerResponse, DeleteSqsTriggerData, DeleteSqsTriggerResponse, GetSqsTriggerData, GetSqsTriggerResponse, ListSqsTriggersData, ListSqsTriggersResponse, ExistsSqsTriggerData, ExistsSqsTriggerResponse, SetSqsTriggerEnabledData, SetSqsTriggerEnabledResponse, TestSqsConnectionData, TestSqsConnectionResponse, CreateMqttTriggerData, CreateMqttTriggerResponse, UpdateMqttTriggerData, UpdateMqttTriggerResponse, DeleteMqttTriggerData, DeleteMqttTriggerResponse, GetMqttTriggerData, GetMqttTriggerResponse, ListMqttTriggersData, ListMqttTriggersResponse, ExistsMqttTriggerData, ExistsMqttTriggerResponse, SetMqttTriggerEnabledData, SetMqttTriggerEnabledResponse, TestMqttConnectionData, TestMqttConnectionResponse, CreateGcpTriggerData, CreateGcpTriggerResponse, UpdateGcpTriggerData, UpdateGcpTriggerResponse, DeleteGcpTriggerData, DeleteGcpTriggerResponse, GetGcpTriggerData, GetGcpTriggerResponse, ListGcpTriggersData, ListGcpTriggersResponse, ExistsGcpTriggerData, ExistsGcpTriggerResponse, SetGcpTriggerEnabledData, SetGcpTriggerEnabledResponse, TestGcpConnectionData, TestGcpConnectionResponse, DeleteGcpSubscriptionData, DeleteGcpSubscriptionResponse, ListGoogleTopicsData, ListGoogleTopicsResponse, ListAllTgoogleTopicSubscriptionsData, ListAllTgoogleTopicSubscriptionsResponse, IsValidPostgresConfigurationData, IsValidPostgresConfigurationResponse, CreateTemplateScriptData, CreateTemplateScriptResponse, GetTemplateScriptData, GetTemplateScriptResponse, ListPostgresReplicationSlotData, ListPostgresReplicationSlotResponse, CreatePostgresReplicationSlotData, CreatePostgresReplicationSlotResponse, DeletePostgresReplicationSlotData, DeletePostgresReplicationSlotResponse, ListPostgresPublicationData, ListPostgresPublicationResponse, GetPostgresPublicationData, GetPostgresPublicationResponse, CreatePostgresPublicationData, CreatePostgresPublicationResponse, UpdatePostgresPublicationData, UpdatePostgresPublicationResponse, DeletePostgresPublicationData, DeletePostgresPublicationResponse, CreatePostgresTriggerData, CreatePostgresTriggerResponse, UpdatePostgresTriggerData, UpdatePostgresTriggerResponse, DeletePostgresTriggerData, DeletePostgresTriggerResponse, GetPostgresTriggerData, GetPostgresTriggerResponse, ListPostgresTriggersData, ListPostgresTriggersResponse, ExistsPostgresTriggerData, ExistsPostgresTriggerResponse, SetPostgresTriggerEnabledData, SetPostgresTriggerEnabledResponse, TestPostgresConnectionData, TestPostgresConnectionResponse, ListInstanceGroupsResponse, GetInstanceGroupData, GetInstanceGroupResponse, CreateInstanceGroupData, CreateInstanceGroupResponse, UpdateInstanceGroupData, UpdateInstanceGroupResponse, DeleteInstanceGroupData, DeleteInstanceGroupResponse, AddUserToInstanceGroupData, AddUserToInstanceGroupResponse, RemoveUserFromInstanceGroupData, RemoveUserFromInstanceGroupResponse, ExportInstanceGroupsResponse, OverwriteInstanceGroupsData, OverwriteInstanceGroupsResponse, ListGroupsData, ListGroupsResponse, ListGroupNamesData, ListGroupNamesResponse, CreateGroupData, CreateGroupResponse, UpdateGroupData, UpdateGroupResponse, DeleteGroupData, DeleteGroupResponse, GetGroupData, GetGroupResponse, AddUserToGroupData, AddUserToGroupResponse, RemoveUserToGroupData, RemoveUserToGroupResponse, ListFoldersData, ListFoldersResponse, ListFolderNamesData, ListFolderNamesResponse, CreateFolderData, CreateFolderResponse, UpdateFolderData, UpdateFolderResponse, DeleteFolderData, DeleteFolderResponse, GetFolderData, GetFolderResponse, ExistsFolderData, ExistsFolderResponse, GetFolderUsageData, GetFolderUsageResponse, AddOwnerToFolderData, AddOwnerToFolderResponse, RemoveOwnerToFolderData, RemoveOwnerToFolderResponse, ListWorkersData, ListWorkersResponse, ExistsWorkerWithTagData, ExistsWorkerWithTagResponse, GetQueueMetricsResponse, GetCountsOfJobsWaitingPerTagResponse, ListWorkerGroupsResponse, GetConfigData, GetConfigResponse, UpdateConfigData, UpdateConfigResponse, DeleteConfigData, DeleteConfigResponse, ListConfigsResponse, ListAutoscalingEventsData, ListAutoscalingEventsResponse, GetGranularAclsData, GetGranularAclsResponse, AddGranularAclsData, AddGranularAclsResponse, RemoveGranularAclsData, RemoveGranularAclsResponse, SetCaptureConfigData, SetCaptureConfigResponse, PingCaptureConfigData, PingCaptureConfigResponse, GetCaptureConfigsData, GetCaptureConfigsResponse, ListCapturesData, ListCapturesResponse, MoveCapturesAndConfigsData, MoveCapturesAndConfigsResponse, GetCaptureData, GetCaptureResponse, DeleteCaptureData, DeleteCaptureResponse, StarData, StarResponse, UnstarData, UnstarResponse, GetInputHistoryData, GetInputHistoryResponse, GetArgsFromHistoryOrSavedInputData, GetArgsFromHistoryOrSavedInputResponse, ListInputsData, ListInputsResponse, CreateInputData, CreateInputResponse, UpdateInputData, UpdateInputResponse, DeleteInputData, DeleteInputResponse, DuckdbConnectionSettingsData, DuckdbConnectionSettingsResponse, DuckdbConnectionSettingsV2Data, DuckdbConnectionSettingsV2Response, PolarsConnectionSettingsData, PolarsConnectionSettingsResponse, PolarsConnectionSettingsV2Data, PolarsConnectionSettingsV2Response, S3ResourceInfoData, S3ResourceInfoResponse, DatasetStorageTestConnectionData, DatasetStorageTestConnectionResponse, ListStoredFilesData, ListStoredFilesResponse, LoadFileMetadataData, LoadFileMetadataResponse, LoadFilePreviewData, LoadFilePreviewResponse, LoadParquetPreviewData, LoadParquetPreviewResponse, LoadTableRowCountData, LoadTableRowCountResponse, LoadCsvPreviewData, LoadCsvPreviewResponse, DeleteS3FileData, DeleteS3FileResponse, MoveS3FileData, MoveS3FileResponse, FileUploadData, FileUploadResponse, FileDownloadData, FileDownloadResponse, FileDownloadParquetAsCsvData, FileDownloadParquetAsCsvResponse, GetJobMetricsData, GetJobMetricsResponse, SetJobProgressData, SetJobProgressResponse, GetJobProgressData, GetJobProgressResponse, ListLogFilesData, ListLogFilesResponse, GetLogFileData, GetLogFileResponse, ListConcurrencyGroupsResponse, DeleteConcurrencyGroupData, DeleteConcurrencyGroupResponse, GetConcurrencyKeyData, GetConcurrencyKeyResponse, ListExtendedJobsData, ListExtendedJobsResponse, SearchJobsIndexData, SearchJobsIndexResponse, SearchLogsIndexData, SearchLogsIndexResponse, CountSearchLogsIndexData, CountSearchLogsIndexResponse, ClearIndexData, ClearIndexResponse } from './types.gen.ts'; /** * get backend version @@ -4753,6 +4753,7 @@ export const runFlowPreview = (data: RunFlowPreviewData): CancelablePromise in postgres) * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.tag filter on jobs with a given tag/worker group * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) @@ -4785,6 +4786,7 @@ export const listQueue = (data: ListQueueData): CancelablePromise in postgres) * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.tag filter on jobs with a given tag/worker group * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) @@ -4904,6 +4907,7 @@ export const listFilteredUuids = (data: ListFilteredUuidsData): CancelablePromis running: data.running, args: data.args, result: data.result, + allow_wildcards: data.allowWildcards, tag: data.tag, page: data.page, per_page: data.perPage, @@ -4950,6 +4954,7 @@ export const cancelSelection = (data: CancelSelectionData): CancelablePromise in postgres) * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.tag filter on jobs with a given tag/worker group * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) @@ -4982,6 +4987,7 @@ export const listCompletedJobs = (data: ListCompletedJobsData): CancelablePromis job_kinds: data.jobKinds, args: data.args, result: data.result, + allow_wildcards: data.allowWildcards, tag: data.tag, page: data.page, per_page: data.perPage, @@ -5018,6 +5024,7 @@ export const listCompletedJobs = (data: ListCompletedJobsData): CancelablePromis * @param data.args filter on jobs containing those args as a json subset (@> in postgres) * @param data.tag filter on jobs with a given tag/worker group * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) * @param data.isSkipped is the job skipped @@ -5058,6 +5065,7 @@ export const listJobs = (data: ListJobsData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/create', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * update gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody updated trigger + * @returns string gcp trigger updated + * @throws ApiError + */ +export const updateGcpTrigger = (data: UpdateGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/update/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * delete gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns string gcp trigger deleted + * @throws ApiError + */ +export const deleteGcpTrigger = (data: DeleteGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'DELETE', + url: '/w/{workspace}/gcp_triggers/delete/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * get gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns GcpTrigger gcp trigger deleted + * @throws ApiError + */ +export const getGcpTrigger = (data: GetGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/get/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * list gcp triggers + * @param data The data for the request. + * @param data.workspace + * @param data.page which page to return (start at 1, default 1) + * @param data.perPage number of items to return for a given page (default 30, max 100) + * @param data.path filter by path + * @param data.isFlow + * @param data.pathStart + * @returns GcpTrigger gcp trigger list + * @throws ApiError + */ +export const listGcpTriggers = (data: ListGcpTriggersData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/list', + path: { + workspace: data.workspace + }, + query: { + page: data.page, + per_page: data.perPage, + path: data.path, + is_flow: data.isFlow, + path_start: data.pathStart + } +}); }; + +/** + * does gcp trigger exists + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns boolean gcp trigger exists + * @throws ApiError + */ +export const existsGcpTrigger = (data: ExistsGcpTriggerData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/exists/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * set enabled gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody updated gcp trigger enable + * @returns string gcp trigger enabled set + * @throws ApiError + */ +export const setGcpTriggerEnabled = (data: SetGcpTriggerEnabledData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/setenabled/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * test gcp connection + * @param data The data for the request. + * @param data.workspace + * @param data.requestBody test gcp connection + * @returns string try to connect to a gcp broker + * @throws ApiError + */ +export const testGcpConnection = (data: TestGcpConnectionData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/test', + path: { + workspace: data.workspace + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * delete gcp trigger + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody args to delete subscription from google cloud + * @returns string gcp trigger deleted + * @throws ApiError + */ +export const deleteGcpSubscription = (data: DeleteGcpSubscriptionData): CancelablePromise => { return __request(OpenAPI, { + method: 'DELETE', + url: '/w/{workspace}/gcp_triggers/subscriptions/delete/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + +/** + * list all topics of google cloud service + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @returns string get all google topics + * @throws ApiError + */ +export const listGoogleTopics = (data: ListGoogleTopicsData): CancelablePromise => { return __request(OpenAPI, { + method: 'GET', + url: '/w/{workspace}/gcp_triggers/topics/list/{path}', + path: { + workspace: data.workspace, + path: data.path + } +}); }; + +/** + * list all subscription of a give topic from google cloud service + * @param data The data for the request. + * @param data.workspace + * @param data.path + * @param data.requestBody args to get subscription's topic from google cloud + * @returns string get all google topic subscriptions name + * @throws ApiError + */ +export const listAllTgoogleTopicSubscriptions = (data: ListAllTgoogleTopicSubscriptionsData): CancelablePromise => { return __request(OpenAPI, { + method: 'POST', + url: '/w/{workspace}/gcp_triggers/subscriptions/list/{path}', + path: { + workspace: data.workspace, + path: data.path + }, + body: data.requestBody, + mediaType: 'application/json' +}); }; + /** * check if postgres configuration is set to logical * @param data The data for the request. @@ -8646,6 +8865,7 @@ export const getConcurrencyKey = (data: GetConcurrencyKeyData): CancelablePromis * @param data.args filter on jobs containing those args as a json subset (@> in postgres) * @param data.tag filter on jobs with a given tag/worker group * @param data.result filter on jobs containing those result as a json subset (@> in postgres) + * @param data.allowWildcards allow wildcards (*) in the filter of label, tag, worker * @param data.page which page to return (start at 1, default 1) * @param data.perPage number of items to return for a given page (default 30, max 100) * @param data.isSkipped is the job skipped @@ -8684,6 +8904,7 @@ export const listExtendedJobs = (data: ListExtendedJobsData): CancelablePromise< args: data.args, tag: data.tag, result: data.result, + allow_wildcards: data.allowWildcards, page: data.page, per_page: data.perPage, is_skipped: data.isSkipped, diff --git a/cli/gen/types.gen.ts b/cli/gen/types.gen.ts index e03d543794..a7924d0b90 100644 --- a/cli/gen/types.gen.ts +++ b/cli/gen/types.gen.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -export type AIProvider = 'openai' | 'anthropic' | 'mistral' | 'deepseek' | 'googleai' | 'groq' | 'openrouter' | 'togetherai' | 'customai'; +export type AIProvider = 'openai' | 'azure_openai' | 'anthropic' | 'mistral' | 'deepseek' | 'googleai' | 'groq' | 'openrouter' | 'togetherai' | 'customai'; export type AIProviderModel = { model: string; @@ -659,6 +659,7 @@ export type TriggersCount = { kafka_count?: number; nats_count?: number; mqtt_count?: number; + gcp_count?: number; sqs_count?: number; }; @@ -774,6 +775,80 @@ export type EditMqttTrigger = { enabled: boolean; }; +export type DeliveryType = 'push' | 'pull'; + +export type PushConfig = { + audience?: string; + authenticate: boolean; + base_endpoint: string; +}; + +export type GcpTrigger = TriggerExtraProperty & { + gcp_resource_path: string; + topic_id: string; + subscription_id: string; + server_id?: string; + delivery_type: DeliveryType; + delivery_config?: PushConfig; + last_server_ping?: string; + error?: string; + enabled: boolean; +}; + +/** + * The mode of subscription. 'existing' means using an existing GCP subscription, while 'create_update' involves creating or updating a new subscription. + */ +export type SubscriptionMode = 'existing' | 'create_update'; + +export type GcpExistingSubscription = { + subscription_id: string; + base_endpoint: string; +}; + +export type GcpCreateUpdateSubscription = { + subscription_id?: string; + delivery_type: DeliveryType; + delivery_config?: PushConfig; +}; + +/** + * "This is a union type representing the subscription mode. + * - 'existing': Represents an existing GCP subscription, and should be accompanied by an 'ExistingGcpSubscription' object. + * - 'create_update': Represents a new or updated GCP subscription, and should be accompanied by a 'CreateUpdateConfig' object." + * + */ +export type GcpSubscriptionModeConfig = (GcpExistingSubscription | GcpCreateUpdateSubscription) & { + subscription_mode: SubscriptionMode; +}; + +export type NewGcpTrigger = { + gcp_resource_path: string; + topic_id: string; + subscription_mode: GcpSubscriptionModeConfig; + path: string; + script_path: string; + is_flow: boolean; + enabled?: boolean; +}; + +export type EditGcpTrigger = { + gcp_resource_path?: string; + topic_id: string; + subscription_mode: GcpSubscriptionModeConfig; + path: string; + script_path: string; + is_flow: boolean; + enabled: boolean; +}; + +export type GetAllTopicSubscription = { + topic_id: string; +}; + +export type DeleteGcpSubscription = { + subscription_id: string; +}; + export type SqsTrigger = TriggerExtraProperty & { queue_url: string; aws_resource_path: string; @@ -1384,7 +1459,7 @@ export type CriticalAlert = { workspace_id?: (string) | null; }; -export type CaptureTriggerKind = 'webhook' | 'http' | 'websocket' | 'kafka' | 'email' | 'nats' | 'postgres' | 'sqs' | 'mqtt'; +export type CaptureTriggerKind = 'webhook' | 'http' | 'websocket' | 'kafka' | 'email' | 'nats' | 'postgres' | 'sqs' | 'mqtt' | 'gcp'; export type Capture = { trigger_kind: CaptureTriggerKind; @@ -1889,6 +1964,11 @@ export type ParameterSuspended = boolean; */ export type ParameterRunning = boolean; +/** + * allow wildcards (*) in the filter of label, tag, worker + */ +export type ParameterAllowWildcards = boolean; + /** * filter on jobs containing those args as a json subset (@> in postgres) */ @@ -2976,6 +3056,7 @@ export type GetUsedTriggersResponse = ({ nats_used: boolean; postgres_used: boolean; mqtt_used: boolean; + gcp_used: boolean; sqs_used: boolean; }); @@ -4983,6 +5064,10 @@ export type RunFlowPreviewData = { export type RunFlowPreviewResponse = (string); export type ListQueueData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ @@ -5108,6 +5193,10 @@ export type CountCompletedJobsData = { export type CountCompletedJobsResponse = (number); export type ListFilteredUuidsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ @@ -5209,6 +5298,10 @@ export type CancelSelectionData = { export type CancelSelectionResponse = (Array<(string)>); export type ListCompletedJobsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * filter on jobs containing those args as a json subset (@> in postgres) */ @@ -5303,6 +5396,10 @@ export type ListCompletedJobsData = { export type ListCompletedJobsResponse = (Array); export type ListJobsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ @@ -6366,6 +6463,124 @@ export type TestMqttConnectionData = { export type TestMqttConnectionResponse = (string); +export type CreateGcpTriggerData = { + /** + * new gcp trigger + */ + requestBody: NewGcpTrigger; + workspace: string; +}; + +export type CreateGcpTriggerResponse = (string); + +export type UpdateGcpTriggerData = { + path: string; + /** + * updated trigger + */ + requestBody: EditGcpTrigger; + workspace: string; +}; + +export type UpdateGcpTriggerResponse = (string); + +export type DeleteGcpTriggerData = { + path: string; + workspace: string; +}; + +export type DeleteGcpTriggerResponse = (string); + +export type GetGcpTriggerData = { + path: string; + workspace: string; +}; + +export type GetGcpTriggerResponse = (GcpTrigger); + +export type ListGcpTriggersData = { + isFlow?: boolean; + /** + * which page to return (start at 1, default 1) + */ + page?: number; + /** + * filter by path + */ + path?: string; + pathStart?: string; + /** + * number of items to return for a given page (default 30, max 100) + */ + perPage?: number; + workspace: string; +}; + +export type ListGcpTriggersResponse = (Array); + +export type ExistsGcpTriggerData = { + path: string; + workspace: string; +}; + +export type ExistsGcpTriggerResponse = (boolean); + +export type SetGcpTriggerEnabledData = { + path: string; + /** + * updated gcp trigger enable + */ + requestBody: { + enabled: boolean; + }; + workspace: string; +}; + +export type SetGcpTriggerEnabledResponse = (string); + +export type TestGcpConnectionData = { + /** + * test gcp connection + */ + requestBody: { + connection: { + [key: string]: unknown; + }; + }; + workspace: string; +}; + +export type TestGcpConnectionResponse = (string); + +export type DeleteGcpSubscriptionData = { + path: string; + /** + * args to delete subscription from google cloud + */ + requestBody: DeleteGcpSubscription; + workspace: string; +}; + +export type DeleteGcpSubscriptionResponse = (string); + +export type ListGoogleTopicsData = { + path: string; + workspace: string; +}; + +export type ListGoogleTopicsResponse = (Array<(string)>); + +export type ListAllTgoogleTopicSubscriptionsData = { + path: string; + /** + * args to get subscription's topic from google cloud + */ + requestBody: GetAllTopicSubscription; + workspace: string; +}; + +export type ListAllTgoogleTopicSubscriptionsResponse = (Array<(string)>); + export type IsValidPostgresConfigurationData = { path: string; workspace: string; @@ -6907,7 +7122,7 @@ export type ListAutoscalingEventsData = { export type ListAutoscalingEventsResponse = (Array); export type GetGranularAclsData = { - kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'sqs_trigger'; + kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'gcp_trigger' | 'sqs_trigger'; path: string; workspace: string; }; @@ -6917,7 +7132,7 @@ export type GetGranularAclsResponse = ({ }); export type AddGranularAclsData = { - kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'sqs_trigger'; + kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'gcp_trigger' | 'sqs_trigger'; path: string; /** * acl to add @@ -6932,7 +7147,7 @@ export type AddGranularAclsData = { export type AddGranularAclsResponse = (string); export type RemoveGranularAclsData = { - kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'sqs_trigger'; + kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow' | 'folder' | 'app' | 'raw_app' | 'http_trigger' | 'websocket_trigger' | 'kafka_trigger' | 'nats_trigger' | 'postgres_trigger' | 'mqtt_trigger' | 'gcp_trigger' | 'sqs_trigger'; path: string; /** * acl to add @@ -6960,7 +7175,9 @@ export type SetCaptureConfigData = { workspace: string; }; -export type SetCaptureConfigResponse = (unknown); +export type SetCaptureConfigResponse = ({ + [key: string]: unknown; +}); export type PingCaptureConfigData = { path: string; @@ -7432,6 +7649,10 @@ export type GetConcurrencyKeyData = { export type GetConcurrencyKeyResponse = (string); export type ListExtendedJobsData = { + /** + * allow wildcards (*) in the filter of label, tag, worker + */ + allowWildcards?: boolean; /** * get jobs from all workspaces (only valid if request come from the `admins` workspace) */ diff --git a/cli/sync.ts b/cli/sync.ts index 82329a77e8..884d0e667e 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -659,7 +659,9 @@ export async function elementsToMap( path.endsWith(".nats_trigger" + ext) || path.endsWith(".postgres_trigger" + ext) || path.endsWith(".mqtt_trigger" + ext) || - path.endsWith(".sqs_trigger" + ext)) + path.endsWith(".sqs_trigger" + ext) || + path.endsWith(".gcp_trigger" + ext) + ) ) continue; if (!skips.includeUsers && path.endsWith(".user" + ext)) continue; @@ -921,7 +923,8 @@ function getOrderFromPath(p: string) { typ == "nats_trigger" || typ == "postgres_trigger" || typ == "mqtt_trigger" || - typ == "sqs_trigger" + typ == "sqs_trigger" || + typ == "gcp_trigger" ) { return 8; } else if (typ == "variable") { @@ -1787,6 +1790,12 @@ export async function push(opts: GlobalOptions & SyncOptions) { path: removeSuffix(target, ".sqs_trigger.json"), }); break; + case "gcp_trigger": + await wmill.deleteGcpTrigger({ + workspace: workspaceId, + path: removeSuffix(target, ".gcp_trigger.json"), + }); + break; case "variable": await wmill.deleteVariable({ workspace: workspaceId, diff --git a/cli/trigger.ts b/cli/trigger.ts index 15e165e1c8..f099885615 100644 --- a/cli/trigger.ts +++ b/cli/trigger.ts @@ -1,5 +1,6 @@ import * as wmill from "./gen/services.gen.ts"; import { + GcpTrigger, HttpTrigger, KafkaTrigger, MqttTrigger, @@ -27,6 +28,7 @@ type Trigger = { postgres: PostgresTrigger; mqtt: MqttTrigger; sqs: SqsTrigger; + gcp: GcpTrigger }; type TriggerFile = Omit< @@ -60,6 +62,7 @@ async function getTrigger( postgres: wmill.getPostgresTrigger, mqtt: wmill.getMqttTrigger, sqs: wmill.getSqsTrigger, + gcp: wmill.getGcpTrigger }; const triggerFunction = triggerFunctions[triggerType]; @@ -87,6 +90,7 @@ async function updateTrigger( postgres: wmill.updatePostgresTrigger, mqtt: wmill.updateMqttTrigger, sqs: wmill.updateSqsTrigger, + gcp: wmill.updateGcpTrigger }; const triggerFunction = triggerFunctions[triggerType]; await triggerFunction({ workspace, path, requestBody: trigger }); @@ -112,6 +116,7 @@ async function createTrigger( postgres: wmill.createPostgresTrigger, mqtt: wmill.createMqttTrigger, sqs: wmill.createSqsTrigger, + gcp: wmill.createGcpTrigger }; const triggerFunction = triggerFunctions[triggerType]; await triggerFunction({ workspace, path, requestBody: trigger }); @@ -191,7 +196,9 @@ async function list(opts: GlobalOptions) { const sqsTriggers = await wmill.listSqsTriggers({ workspace: workspace.workspaceId, }); - + const gcpTriggers = await wmill.listGcpTriggers({ + workspace: workspace.workspaceId + }) const triggers = [ ...httpTriggers.map((x) => ({ path: x.path, kind: "http" })), ...websocketTriggers.map((x) => ({ path: x.path, kind: "websocket" })), @@ -200,6 +207,7 @@ async function list(opts: GlobalOptions) { ...postgresTriggers.map((x) => ({ path: x.path, kind: "postgres" })), ...mqttTriggers.map((x) => ({ path: x.path, kind: "mqtt" })), ...sqsTriggers.map((x) => ({ path: x.path, kind: "sqs" })), + ...gcpTriggers.map((x) => ({ path: x.path, kind: "gcp" })) ]; new Table() @@ -213,7 +221,7 @@ async function list(opts: GlobalOptions) { function checkIfValidTrigger(kind: string | undefined): kind is TriggerType { if ( kind && - ["http", "websocket", "kafka", "nats", "postgres", "mqtt", "sqs"].includes(kind) + ["http", "websocket", "kafka", "nats", "postgres", "mqtt", "sqs", "gcp"].includes(kind) ) { return true; } else { diff --git a/cli/types.ts b/cli/types.ts index 4b08a5805c..a95be8da98 100644 --- a/cli/types.ts +++ b/cli/types.ts @@ -154,6 +154,8 @@ export async function pushObj( await pushTrigger("mqtt", workspace, p, befObj, newObj); } else if (typeEnding === "sqs_trigger") { await pushTrigger("sqs", workspace, p, befObj, newObj); + } else if (typeEnding === "gcp_trigger") { + await pushTrigger("gcp", workspace, p, befObj, newObj); } else if (typeEnding === "user") { await pushWorkspaceUser(workspace, p, befObj, newObj); } else if (typeEnding === "group") { @@ -203,6 +205,7 @@ export function getTypeStrFromPath( | "postgres_trigger" | "mqtt_trigger" | "sqs_trigger" + | "gcp_trigger" | "user" | "group" | "settings" @@ -253,6 +256,7 @@ export function getTypeStrFromPath( typeEnding === "postgres_trigger" || typeEnding === "mqtt_trigger" || typeEnding === "sqs_trigger" || + typeEnding === "gcp_trigger" || typeEnding === "user" || typeEnding === "group" || typeEnding === "settings" || diff --git a/frontend/src/lib/components/DeployWorkspace.svelte b/frontend/src/lib/components/DeployWorkspace.svelte index 28a039f1b0..b4938cd927 100644 --- a/frontend/src/lib/components/DeployWorkspace.svelte +++ b/frontend/src/lib/components/DeployWorkspace.svelte @@ -230,7 +230,8 @@ 'routes', 'schedules', 'sqs', - 'websockets' + 'websockets', + 'gcp' ] if ( additionalInformation?.triggers && diff --git a/frontend/src/lib/components/Path.svelte b/frontend/src/lib/components/Path.svelte index 15688aa026..08af2df548 100644 --- a/frontend/src/lib/components/Path.svelte +++ b/frontend/src/lib/components/Path.svelte @@ -20,7 +20,9 @@ PostgresTriggerService, NatsTriggerService, MqttTriggerService, - SqsTriggerService + SqsTriggerService, + GcpTriggerService + } from '$lib/gen' import { superadmin, userStore, workspaceStore } from '$lib/stores' import { createEventDispatcher, getContext } from 'svelte' @@ -49,6 +51,7 @@ | 'nats_trigger' | 'mqtt_trigger' | 'sqs_trigger' + | 'gcp_trigger' let meta: Meta | undefined = undefined export let fullNamePlaceholder: string | undefined = undefined export let namePlaceholder = '' @@ -262,6 +265,11 @@ workspace: $workspaceStore!, path: path }) + } else if (kind === 'gcp_trigger') { + return await GcpTriggerService.existsGcpTrigger({ + workspace: $workspaceStore!, + path: path + }) } else { return false } diff --git a/frontend/src/lib/components/ShareModal.svelte b/frontend/src/lib/components/ShareModal.svelte index 38f9c58d50..07179e06d7 100644 --- a/frontend/src/lib/components/ShareModal.svelte +++ b/frontend/src/lib/components/ShareModal.svelte @@ -31,6 +31,7 @@ | 'mqtt_trigger' | 'sqs_trigger' | 'postgres_trigger' + | 'gcp_trigger' let kind: Kind let path: string = '' diff --git a/frontend/src/lib/components/details/DetailPageDetailPanel.svelte b/frontend/src/lib/components/details/DetailPageDetailPanel.svelte index 9176099115..64433c1f47 100644 --- a/frontend/src/lib/components/details/DetailPageDetailPanel.svelte +++ b/frontend/src/lib/components/details/DetailPageDetailPanel.svelte @@ -17,6 +17,7 @@ | 'kafka' | 'mqtt' | 'sqs' + | 'gcp' | 'nats' = 'webhooks' export let flow_json: any | undefined = undefined export let simplfiedPoll: boolean = false @@ -61,6 +62,7 @@ + diff --git a/frontend/src/lib/components/details/DetailPageLayout.svelte b/frontend/src/lib/components/details/DetailPageLayout.svelte index b102ebffdf..b8d3c03f67 100644 --- a/frontend/src/lib/components/details/DetailPageLayout.svelte +++ b/frontend/src/lib/components/details/DetailPageLayout.svelte @@ -32,6 +32,7 @@ | 'nats' | 'mqtt' | 'sqs' + | 'gcp' >('webhooks') const simplifiedPoll = writable(false) @@ -71,6 +72,7 @@ + @@ -120,6 +122,7 @@ + diff --git a/frontend/src/lib/components/details/DetailPageTriggerPanel.svelte b/frontend/src/lib/components/details/DetailPageTriggerPanel.svelte index e4baffd14b..6bfeb9f3e0 100644 --- a/frontend/src/lib/components/details/DetailPageTriggerPanel.svelte +++ b/frontend/src/lib/components/details/DetailPageTriggerPanel.svelte @@ -15,6 +15,7 @@ import ToggleButtonGroup from '../common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '../common/toggleButton-v2/ToggleButton.svelte' import { MqttIcon, NatsIcon, KafkaIcon, AwsIcon } from '../icons' + import GoogleCloudIcon from '../icons/GoogleCloudIcon.svelte' export let triggerSelected: | 'webhooks' @@ -28,17 +29,19 @@ | 'nats' | 'sqs' | 'mqtt' + | 'gcp' | 'scheduledPoll' = 'webhooks' export let simplfiedPoll: boolean = false - export let eventStreamType: 'kafka' | 'nats' | 'sqs' | 'mqtt' = 'kafka' + export let eventStreamType: 'kafka' | 'nats' | 'sqs' | 'mqtt' | 'gcp' = 'kafka' $: { if ( triggerSelected === 'kafka' || triggerSelected === 'nats' || triggerSelected === 'sqs' || - triggerSelected === 'mqtt' + triggerSelected === 'mqtt' || + triggerSelected === 'gcp' ) { eventStreamType = triggerSelected } @@ -80,7 +83,7 @@ Postgres - + Event streams @@ -113,13 +116,14 @@ {:else if triggerSelected === 'postgres'} - {:else if triggerSelected === 'kafka' || triggerSelected === 'nats' || triggerSelected === 'sqs' || triggerSelected === 'mqtt'} + {:else if triggerSelected === 'kafka' || triggerSelected === 'nats' || triggerSelected === 'sqs' || triggerSelected === 'mqtt' || triggerSelected === 'gcp'}
+
{#if eventStreamType === 'kafka'} @@ -130,6 +134,8 @@ {:else if eventStreamType === 'mqtt'} + {:else if eventStreamType === 'gcp'} + {/if} {:else if triggerSelected === 'cli'} diff --git a/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte b/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte index 86fe790910..0ed191d335 100644 --- a/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte +++ b/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte @@ -11,6 +11,7 @@ import { FlowService, ScriptService } from '$lib/gen' import { enterpriseLicense, workspaceStore } from '$lib/stores' import { MqttIcon, NatsIcon, KafkaIcon, AwsIcon } from '$lib/components/icons' + import GoogleCloudIcon from '$lib/components/icons/GoogleCloudIcon.svelte' const { selectedTrigger, triggersCount } = getContext('TriggerContext') @@ -31,6 +32,7 @@ | 'eventStreams' | 'postgres' | 'sqs' + | 'gcp' )[] = showOnlyWithCount ? ['webhooks', 'schedules', 'routes', 'websockets', 'kafka', 'nats', 'emails'] : ['webhooks', 'schedules', 'routes', 'websockets', 'eventStreams', 'emails'] @@ -69,6 +71,7 @@ nats: { icon: NatsIcon, countKey: 'nats_count' }, mqtt: { icon: MqttIcon, countKey: 'mqtt_count' }, sqs: { icon: AwsIcon, countKey: 'sqs_count' }, + gcp: { icon: GoogleCloudIcon, countKey: 'gcp_count' }, eventStreams: { icon: PlugZap } } @@ -80,7 +83,7 @@ {#each triggersToDisplay as type} {@const { icon, countKey } = triggerTypeConfig[type]} - {#if (!showOnlyWithCount || ((countKey && $triggersCount?.[countKey]) || 0) > 0) && !(type === 'sqs' && !$enterpriseLicense) && !(type === 'kafka' && !$enterpriseLicense) && !(type === 'nats' && !$enterpriseLicense) && !(type === 'mqtt')} + {#if (!showOnlyWithCount || ((countKey && $triggersCount?.[countKey]) || 0) > 0) && !(type === 'gcp' && !$enterpriseLicense) && !(type === 'sqs' && !$enterpriseLicense) && !(type === 'kafka' && !$enterpriseLicense) && !(type === 'nats' && !$enterpriseLicense) && !(type === 'mqtt')} {camelCaseToWords(type)} {#if countKey} diff --git a/frontend/src/lib/components/icons/GoogleCloudIcon.svelte b/frontend/src/lib/components/icons/GoogleCloudIcon.svelte index 26c3570eac..398fb378ee 100644 --- a/frontend/src/lib/components/icons/GoogleCloudIcon.svelte +++ b/frontend/src/lib/components/icons/GoogleCloudIcon.svelte @@ -1,21 +1,33 @@ - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/frontend/src/lib/components/sidebar/OperatorMenu.svelte b/frontend/src/lib/components/sidebar/OperatorMenu.svelte index 4eecd8590d..a067be58f0 100644 --- a/frontend/src/lib/components/sidebar/OperatorMenu.svelte +++ b/frontend/src/lib/components/sidebar/OperatorMenu.svelte @@ -89,6 +89,11 @@ id: 'triggers', href: `${base}/sqs_triggers` }, + { + label: 'GCP Pub/Sub triggers', + id: 'triggers', + href: `${base}/gcp_triggers` + }, { label: 'MQTT triggers', id: 'triggers', diff --git a/frontend/src/lib/components/sidebar/SidebarContent.svelte b/frontend/src/lib/components/sidebar/SidebarContent.svelte index 7d9564065a..2c4d32139e 100644 --- a/frontend/src/lib/components/sidebar/SidebarContent.svelte +++ b/frontend/src/lib/components/sidebar/SidebarContent.svelte @@ -60,6 +60,7 @@ MeltButton } from '$lib/components/meltComponents' import MenuButton from './MenuButton.svelte' + import GoogleCloudIcon from '../icons/GoogleCloudIcon.svelte' export let numUnacknowledgedCriticalAlerts = 0 @@ -136,13 +137,20 @@ disabled: $userStore?.operator || !$enterpriseLicense, kind: 'sqs' }, + { + label: 'GCP Pub/Sub' + ($enterpriseLicense ? '' : ' (EE)'), + href: '/gcp_triggers', + icon: GoogleCloudIcon, + disabled: $userStore?.operator || !$enterpriseLicense, + kind: 'gcp' + }, { label: 'MQTT', href: '/mqtt_triggers', icon: MqttIcon, disabled: $userStore?.operator, kind: 'mqtt' - }, + } ] $: extraTriggerLinks = defaultExtraTriggerLinks.filter((link) => { diff --git a/frontend/src/lib/components/triggers.ts b/frontend/src/lib/components/triggers.ts index 4d5a70e9a0..ad3ded6b1d 100644 --- a/frontend/src/lib/components/triggers.ts +++ b/frontend/src/lib/components/triggers.ts @@ -54,6 +54,7 @@ export type TriggerKind = | 'postgres' | 'mqtt' | 'sqs' + | 'gcp' export function captureTriggerKindToTriggerKind(kind: CaptureTriggerKind): TriggerKind { switch (kind) { case 'webhook': @@ -74,6 +75,8 @@ export function captureTriggerKindToTriggerKind(kind: CaptureTriggerKind): Trigg return 'sqs' case 'postgres': return 'postgres' + case 'gcp': + return 'gcp' default: throw new Error(`Unknown CaptureTriggerKind: ${kind}`) } diff --git a/frontend/src/lib/components/triggers/CaptureButton.svelte b/frontend/src/lib/components/triggers/CaptureButton.svelte index bfa34cf908..a5d89792ab 100644 --- a/frontend/src/lib/components/triggers/CaptureButton.svelte +++ b/frontend/src/lib/components/triggers/CaptureButton.svelte @@ -11,6 +11,7 @@ import AwsIcon from '../icons/AwsIcon.svelte' import DropdownV2 from '$lib/components/DropdownV2.svelte' import MqttIcon from '../icons/MqttIcon.svelte' + import GoogleCloudIcon from '../icons/GoogleCloudIcon.svelte' export let small = false @@ -45,6 +46,12 @@ action: () => handleClick('sqs'), disabled: !$enterpriseLicense }, + { + icon: GoogleCloudIcon, + displayName: 'GCP Pub/Sub', + action: () => handleClick('gcp'), + disabled: !$enterpriseLicense + }, { icon: MqttIcon, displayName: 'MQTT', diff --git a/frontend/src/lib/components/triggers/CaptureSection.svelte b/frontend/src/lib/components/triggers/CaptureSection.svelte index 4331586190..1237683dcc 100644 --- a/frontend/src/lib/components/triggers/CaptureSection.svelte +++ b/frontend/src/lib/components/triggers/CaptureSection.svelte @@ -6,6 +6,7 @@ isFlow: boolean path: string connectionInfo: ConnectionInfo | undefined + loading?: boolean } @@ -70,7 +71,11 @@
- +
{/key} diff --git a/frontend/src/lib/components/triggers/TestTriggerConnection.svelte b/frontend/src/lib/components/triggers/TestTriggerConnection.svelte index eeb2c1d74b..31dc66dffa 100644 --- a/frontend/src/lib/components/triggers/TestTriggerConnection.svelte +++ b/frontend/src/lib/components/triggers/TestTriggerConnection.svelte @@ -6,13 +6,14 @@ NatsTriggerService, SqsTriggerService, PostgresTriggerService, - WebsocketTriggerService + WebsocketTriggerService, + GcpTriggerService } from '$lib/gen' import { workspaceStore } from '$lib/stores' import { sendUserToast } from '$lib/toast' import Button from '../common/button/Button.svelte' - export let kind: 'websocket' | 'nats' | 'kafka' | 'postgres' | 'sqs' | 'mqtt' + export let kind: 'websocket' | 'nats' | 'kafka' | 'postgres' | 'sqs' | 'mqtt' | 'gcp' export let args: Record export let noButton = false export let testLoading: boolean = false @@ -23,7 +24,8 @@ kafka: 'Kafka broker(s)', sqs: 'SQS', postgres: 'Postgres', - mqtt: 'MQTT broker' + mqtt: 'MQTT broker', + gcp: 'Google Cloud Pub/Sub' } let promise: CancelablePromise | null = null @@ -65,6 +67,11 @@ workspace: $workspaceStore!, requestBody: args as any }) + } else if (kind === 'gcp') { + promise = GcpTriggerService.testGcpConnection({ + workspace: $workspaceStore!, + requestBody: args as any + }) } await promise sendUserToast(`Successfully connected to ${kindToName[kind]}`) diff --git a/frontend/src/lib/components/triggers/TriggersEditor.svelte b/frontend/src/lib/components/triggers/TriggersEditor.svelte index 9e3bcb9db9..7b4968d77c 100644 --- a/frontend/src/lib/components/triggers/TriggersEditor.svelte +++ b/frontend/src/lib/components/triggers/TriggersEditor.svelte @@ -15,11 +15,12 @@ import PostgresTriggersPanel from './postgres/PostgresTriggersPanel.svelte' import ToggleButtonGroup from '../common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '../common/toggleButton-v2/ToggleButton.svelte' - import { KafkaIcon, MqttIcon, NatsIcon, AwsIcon } from '../icons' + import { KafkaIcon, MqttIcon, NatsIcon, AwsIcon, GoogleCloudIcon } from '../icons' import KafkaTriggersPanel from './kafka/KafkaTriggersPanel.svelte' import NatsTriggersPanel from './nats/NatsTriggersPanel.svelte' import MqttTriggersPanel from './mqtt/MqttTriggersPanel.svelte' import SqsTriggerPanel from './sqs/SqsTriggerPanel.svelte' + import GcpTriggerPanel from './gcp/GcpTriggerPanel.svelte' export let noEditor: boolean export let newItem = false @@ -32,14 +33,15 @@ export let canHavePreprocessor: boolean = false export let hasPreprocessor: boolean = false export let args: Record = {} - let eventStreamType: 'kafka' | 'nats' | 'sqs' | 'mqtt' = 'kafka' + let eventStreamType: 'kafka' | 'nats' | 'sqs' | 'mqtt' | 'gcp' = 'kafka' $: { if ( $selectedTrigger === 'kafka' || $selectedTrigger === 'nats' || $selectedTrigger === 'sqs' || - $selectedTrigger === 'mqtt' + $selectedTrigger === 'mqtt' || + $selectedTrigger === 'gcp' ) { eventStreamType = $selectedTrigger } @@ -64,7 +66,7 @@ Postgres Event streams @@ -160,13 +162,14 @@ isEditor={true} />
- {:else if $selectedTrigger === 'kafka' || $selectedTrigger === 'nats' || $selectedTrigger === 'sqs' || $selectedTrigger === 'mqtt'} + {:else if $selectedTrigger === 'kafka' || $selectedTrigger === 'nats' || $selectedTrigger === 'sqs' || $selectedTrigger === 'mqtt' || $selectedTrigger === 'gcp'}
+ {#if eventStreamType === 'kafka'} + {:else if eventStreamType === 'gcp'} + {/if}
{:else if $selectedTrigger === 'schedules'} diff --git a/frontend/src/lib/components/triggers/TriggersEditorSection.svelte b/frontend/src/lib/components/triggers/TriggersEditorSection.svelte index 3336568893..c6e1f0ba2d 100644 --- a/frontend/src/lib/components/triggers/TriggersEditorSection.svelte +++ b/frontend/src/lib/components/triggers/TriggersEditorSection.svelte @@ -26,15 +26,16 @@ export let showCapture: boolean = false const captureTypeLabels: Record = { - http: '+ New custom HTTP route', - websocket: '+ New WebSocket trigger', + http: 'custom HTTP route', + websocket: 'WebSocket trigger', webhook: 'Webhook', - kafka: '+ New Kafka trigger', + kafka: 'Kafka trigger', email: 'Email trigger', - nats: '+ New NATS trigger', - mqtt: '+ New MQTT trigger', - sqs: '+ New SQS trigger', - postgres: '+ New Postgres trigger' + nats: 'NATS trigger', + mqtt: 'MQTT trigger', + sqs: 'SQS trigger', + postgres: 'Postgres trigger', + gcp: 'GCP Pub/Sub trigger' } const { captureOn } = getContext('TriggerContext') @@ -55,7 +56,11 @@ } -
+
{#if !collapsed || alwaysOpened}
diff --git a/frontend/src/lib/components/triggers/TriggersWrapper.svelte b/frontend/src/lib/components/triggers/TriggersWrapper.svelte index e9a17c10dc..06decadd5e 100644 --- a/frontend/src/lib/components/triggers/TriggersWrapper.svelte +++ b/frontend/src/lib/components/triggers/TriggersWrapper.svelte @@ -11,6 +11,7 @@ import MqttEditorConfigSection from './mqtt/MqttEditorConfigSection.svelte' import SqsTriggerEditorConfigSection from './sqs/SqsTriggerEditorConfigSection.svelte' import PostgresEditorConfigSection from './postgres/PostgresEditorConfigSection.svelte' + import GcpTriggerEditorConfigSection from './gcp/GcpTriggerEditorConfigSection.svelte' export let triggerType: CaptureTriggerKind = 'webhook' export let cloudDisabled: boolean = false @@ -96,5 +97,20 @@ can_write={true} showCapture={false} /> + {:else if triggerType === 'gcp'} + {/if}
diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditor.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditor.svelte new file mode 100644 index 0000000000..1b2f8cf389 --- /dev/null +++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditor.svelte @@ -0,0 +1,27 @@ + + +{#if open} + +{/if} diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte new file mode 100644 index 0000000000..d359085122 --- /dev/null +++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte @@ -0,0 +1,342 @@ + + + + +
+ {#if showCapture && captureInfo} + {@const captureURL = `${base_endpoint}/${path}`} + + {#if delivery_type === 'push'} + + {/if} + + {/if} +
+
+ +
+ { + loadAllPubSubTopicsFromProject() + }} + resourceType="gcloud" + bind:value={gcp_resource_path} + /> + {#if !emptyStringTrimmed(gcp_resource_path)} + + {/if} +
+
+ +
+ +
+ { + subscription_id = event?.currentTarget.value + }} + /> +
+
+
+ +
+ + + + +
+
+ {#if delivery_type === 'push' && delivery_config} +
+ +
+ + +
+
+ + + + +

+ Enable Google Cloud authentication for push delivery using a verified token. +

+ +
+
+ {/if} +
+ {:else if subscription_mode === 'existing'} +
+
+ +
+
Filter by path of
+ + + + +
+ + +
+ {#if $userStore?.is_super_admin && $userStore.username.includes('@')} + + {:else if $userStore?.is_admin || $userStore?.is_super_admin} + + {/if} +
+
+ {#if loading} + {#each new Array(6) as _} + + {/each} + {:else if !triggers?.length} +
No GCP Pub/Sub triggers
+ {:else if items?.length} +
+ {#each items.slice(0, nbDisplayed) as { gcp_resource_path, topic_id, workspace_id, delivery_type, path, edited_by, error, edited_at, script_path, is_flow, extra_perms, canWrite, enabled, server_id, subscription_id } (path)} + {@const href = `${is_flow ? '/flows/get' : '/scripts/get'}/${script_path}`} + {@const ping = new Date()} + {@const pinging = ping && ping.getTime() > new Date().getTime() - 15 * 1000} + +
+
+ + + gcpTriggerEditor?.openEdit(path, is_flow)} + class="min-w-0 grow hover:underline decoration-gray-400" + > +
+ {path} - {topic_id} +
+
+ runnable: {script_path} +
+
+ + + + {#if delivery_type !== 'push'} +
+ {#if (enabled && (!pinging || error)) || (!enabled && error) || (enabled && !server_id)} + + + + + +
+ {#if enabled} + {#if !server_id} + GCP Pub/Sub trigger is starting... + {:else} + Could not connect to GCP Pub/Sub{error ? ': ' + error : ''} + {/if} + {:else} + Disabled because of an error: {error} + {/if} +
+
+ {:else if enabled} + + + + +
+ Connected to GCP Pub/Sub{!server_id ? ' (shutting down...)' : ''}
+
+ {/if} +
+ {/if} + + {#if delivery_type !== 'push'} + { + setTriggerEnabled(path, e.detail) + }} + /> + {/if} + +
+ {#if delivery_type === 'push'} + + {/if} + + { + goto(href) + } + }, + { + displayName: 'Delete', + type: 'delete', + icon: Trash, + disabled: !canWrite, + action: async () => { + isDeleting = false + deleteSubscription = false + subscriptionToDelete = subscription_id + currentTopic = topic_id + deleteSubscriptionCallback = async () => { + const message = await GcpTriggerService.deleteGcpSubscription({ + workspace: $workspaceStore ?? '', + path: gcp_resource_path, + requestBody: { + subscription_id + } + }) + sendUserToast(message) + } + deleteGcpTriggerCallback = async () => { + const message = await GcpTriggerService.deleteGcpTrigger({ + workspace: $workspaceStore ?? '', + path + }) + sendUserToast(message) + loadTriggers() + } + } + }, + { + displayName: canWrite ? 'Edit' : 'View', + icon: canWrite ? Pen : Eye, + action: () => { + gcpTriggerEditor?.openEdit(path, is_flow) + } + }, + ...(isDeployable('trigger', path, deployUiSettings) + ? [ + { + displayName: 'Deploy to prod/staging', + icon: FileUp, + action: () => { + deploymentDrawer.openDrawer(path, 'trigger', { + triggers: { + kind: 'gcp' + } + }) + } + } + ] + : []), + { + displayName: 'Audit logs', + icon: Eye, + href: `${base}/audit_logs?resource=${path}` + }, + { + displayName: canWrite ? 'Share' : 'See Permissions', + icon: Share, + action: () => { + shareModal.openDrawer(path, 'gcp_trigger') + } + } + ]} + /> +
+
+
+
edited by {edited_by}
the {displayDate(edited_at)}
+
+ {/each} +
+ {:else} + + {/if} +
+ {#if items && items?.length > 15 && nbDisplayed < items.length} + {nbDisplayed} items out of {items.length} + + {/if} + + + { + loadTriggers() + }} +/> diff --git a/frontend/src/routes/(root)/(logged)/routes/+page.svelte b/frontend/src/routes/(root)/(logged)/routes/+page.svelte index a43cfdd86f..1a33fae1be 100644 --- a/frontend/src/routes/(root)/(logged)/routes/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/routes/+page.svelte @@ -283,7 +283,9 @@
+ +
+ +
+