Compare commits

...
Author SHA1 Message Date
Ruben Fiszelandrubenfiszel 6d63d9973d chore(main): release 1.663.0 (#8465)
* chore(main): release 1.663.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2026-03-24 13:31:06 +00:00
Rogelio Alcala Ortiz 23df390b17 allow modern email TLDs in superadmin setup form (#8472) 2026-03-24 13:27:41 +00:00
hugocasaandClaude Opus 4.6 5089a45881 feat: add summary field for native triggers (#8476)
* feat: add summary field for native triggers (nextcloud, google)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add nullable to NativeTriggerData summary in openapi spec

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: include summary in native trigger search index

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:27:09 +00:00
hugocasaandClaude Opus 4.6 f035b538bb feat: surface permissioned_as selector in trigger editor UI (#8475)
* feat: surface permissioned_as selector in trigger editor UI

Add OnBehalfOfSelector to TriggerEditorToolbar so users can see and
control who a trigger runs as. Admins/deployers can preserve the
current permissioned_as or pick a custom user; non-admins see the
current value but options are disabled.

Applies to all trigger types: schedule, kafka, http, websocket,
postgres, nats, mqtt, sqs, gcp, and email.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: move permissioned_as selector from toolbar to config area

Move OnBehalfOfSelector out of TriggerEditorToolbar (too cluttered)
into a new PermissionedAsLine component rendered at the top of each
trigger editor's config body. Lighter footprint, same functionality.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: show explicit warning when saving will change permissioned_as

Use an Alert (warning/info) to clearly show who the trigger currently
runs as and whether saving will change it. Non-admin users see a
warning that it will switch to them. Admins see the OnBehalfOfSelector
to preserve or pick a custom user.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: make permissioned_as line subtle instead of big alert box

Replace the Alert component with a small inline text line using
text-2xs. Shows warning arrow + yellow text only when saving will
actually change the permissioned_as.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: split permissioned_as display for admin vs non-admin

Admins see just "Permissioned as" label + the OnBehalfOfSelector
(no duplicate username). Non-admins see the plain text line with
warning arrow when it will change.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: show warning for admins too when permissioned_as will change

Admins now see a yellow warning next to the selector when their
choice differs from the current permissioned_as value.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use consistent warning text for permissioned_as change

Both admin and non-admin warnings now say
"will change to <user> on save" instead of using an arrow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: bold permission strings in permissioned_as warnings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: bold the non-editable permissioned_as value too

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove mono font from non-editable permissioned_as value

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add consistent bottom margin to permissioned_as line

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: consistent spacing for permissioned_as line

Move PermissionedAsLine outside the gap-8 div in schedule editor
and increase margin to mb-4 for consistent spacing across all
trigger types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:26:56 +00:00
hugocasaandClaude Opus 4.6 47c0c363f4 fix: clean up stale dependency map entries for renamed scripts (#8492)
* fix: clean up stale dependency map entries for renamed scripts

When a script is renamed, trigger_dependents_to_recompute_dependencies()
could find the archived script at the old path and create a dependency
job for it. This job would process the old code and recreate stale
dependency_map entries, causing incorrect deployment warnings.

Add `AND archived = false` to the script lookup query so that renamed
(archived) scripts at old paths trigger clear_map_for_item() cleanup
instead of spawning dependency jobs for obsolete code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: also filter archived flows in trigger_dependents

Apply the same archived check to the flow lookup query. The flow table
has an archived column, so when a flow is renamed/archived its
flow_version rows would still be found. Join against the flow table
and filter archived = false to trigger cleanup instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* revert: remove unnecessary flow archived check

Flow renames delete the old flow row and INSERT a new one at the new
path (for FK constraints on flow_version). There is no archived flow
row left behind, so the original query is already correct for flows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:25:07 +00:00
Ruben FiszelandClaude Opus 4.6 54f5a19377 fix: prevent SQL injection in job query parameters (#8494)
Replace unsafe string interpolation (format!("'{}'", t)) with
sql_builder::quote() in SQL query construction. The tags parameter in
count_completed_jobs_detail was directly interpolated without escaping,
allowing authenticated users to inject arbitrary SQL via the query string.

Also hardens LIKE clauses, JSON operators, and JOIN conditions across
query.rs and variables.rs that used manual .replace("'", "''") instead
of the crate's quote() function, and converts format-interpolated bind
values to parameterized queries where possible.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:23:43 +00:00
59 changed files with 666 additions and 262 deletions
+25
View File
@@ -1,5 +1,30 @@
# Changelog
## [1.663.0](https://github.com/windmill-labs/windmill/compare/v1.662.0...v1.663.0) (2026-03-24)
### Features
* add summary field for native triggers ([#8476](https://github.com/windmill-labs/windmill/issues/8476)) ([5089a45](https://github.com/windmill-labs/windmill/commit/5089a458819abbc6f241bc354bebb91520bd1a52))
* add typed request body to OpenAPI spec generation ([#8481](https://github.com/windmill-labs/windmill/issues/8481)) ([37ebaf4](https://github.com/windmill-labs/windmill/commit/37ebaf4d0ac342703498733f97778a552f979f6a))
* **cli:** better stale scripts detection [#3](https://github.com/windmill-labs/windmill/issues/3) ([#8480](https://github.com/windmill-labs/windmill/issues/8480)) ([9643006](https://github.com/windmill-labs/windmill/commit/9643006f1e90b991b334bb58caf62301bc26d09d))
* Debounce node ([#8324](https://github.com/windmill-labs/windmill/issues/8324)) ([5d1c54d](https://github.com/windmill-labs/windmill/commit/5d1c54d9b33d6ff6f2c98481a2740d1e7629cdfa))
* surface permissioned_as selector in trigger editor UI ([#8475](https://github.com/windmill-labs/windmill/issues/8475)) ([f035b53](https://github.com/windmill-labs/windmill/commit/f035b538bbd786445526339f88be8f33a3628105))
### Bug Fixes
* clean up stale dependency map entries for renamed scripts ([#8492](https://github.com/windmill-labs/windmill/issues/8492)) ([47c0c36](https://github.com/windmill-labs/windmill/commit/47c0c363f4fc1d9af7efd07ea172e32989ce50d2))
* **cli:** add Svelte 5 event delegation guidance and safe push to raw-app skill ([#8466](https://github.com/windmill-labs/windmill/issues/8466)) ([911df95](https://github.com/windmill-labs/windmill/commit/911df958e78d2dab9823dfa7d7e5c9824fc2d565))
* Fix worker panic when job_isolation changed to unshare at runtime ([#8490](https://github.com/windmill-labs/windmill/issues/8490)) ([cbe47c0](https://github.com/windmill-labs/windmill/commit/cbe47c0b6c22f79452d020777e481ee26970f25b))
* improve SQS retries ([3c8d351](https://github.com/windmill-labs/windmill/commit/3c8d351c9722a089133871019d27cf3bc3cdc159))
* Move database manager SQL queries to backend ([#8306](https://github.com/windmill-labs/windmill/issues/8306)) ([aa30fd2](https://github.com/windmill-labs/windmill/commit/aa30fd252dcf40233d191c43a6293fb9feabf010))
* prevent SQL injection in job query parameters ([#8494](https://github.com/windmill-labs/windmill/issues/8494)) ([54f5a19](https://github.com/windmill-labs/windmill/commit/54f5a19377e9df712e18f85f896e21b1776981ed))
* respect NO_COLOR env variable for stdout log output ([#8483](https://github.com/windmill-labs/windmill/issues/8483)) ([f329ee7](https://github.com/windmill-labs/windmill/commit/f329ee7aaefbae0ad344743c40825440a936bd30))
* show effective isolation level on workers page ([#8491](https://github.com/windmill-labs/windmill/issues/8491)) ([37886ed](https://github.com/windmill-labs/windmill/commit/37886edda1443293806a9b1b810196b72e076b12))
* skip debounce arg accumulation when batch table is empty (CE) ([#8485](https://github.com/windmill-labs/windmill/issues/8485)) ([010753c](https://github.com/windmill-labs/windmill/commit/010753c73ac85237af50acadf9c08567b1bc993c))
* stop_after_if with empty error_message prevents flow from stopping ([#8464](https://github.com/windmill-labs/windmill/issues/8464)) ([1503bf9](https://github.com/windmill-labs/windmill/commit/1503bf948e3340b8a6933d71885f8f2cb8dc1867))
## [1.662.0](https://github.com/windmill-labs/windmill/compare/v1.661.0...v1.662.0) (2026-03-20)
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO native_trigger (\n external_id,\n workspace_id,\n service_name,\n script_path,\n is_flow,\n webhook_token_hash,\n service_config\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ON CONFLICT (external_id, workspace_id, service_name)\n DO UPDATE SET script_path = $4, is_flow = $5, webhook_token_hash = $6, service_config = $7, error = NULL, updated_at = NOW()\n ",
"query": "\n INSERT INTO native_trigger (\n external_id,\n workspace_id,\n service_name,\n script_path,\n is_flow,\n webhook_token_hash,\n service_config,\n summary\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8\n )\n ON CONFLICT (external_id, workspace_id, service_name)\n DO UPDATE SET script_path = $4, is_flow = $5, webhook_token_hash = $6, service_config = $7, summary = $8, error = NULL, updated_at = NOW()\n ",
"describe": {
"columns": [],
"parameters": {
@@ -21,10 +21,11 @@
"Varchar",
"Bool",
"Varchar",
"Jsonb"
"Jsonb",
"Varchar"
]
},
"nullable": []
},
"hash": "6f9386dfcb4c201525722aee3caa25bf2f3a35d90f7354c7d3aef8a3538a03a7"
"hash": "1048d1c95270ce1f36c02bce31a2bc8a88935c613bd213b7156299811377db8e"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n external_id,\n workspace_id,\n service_name AS \"service_name!: ServiceName\",\n script_path,\n is_flow,\n webhook_token_hash,\n service_config,\n error,\n created_at,\n updated_at\n FROM\n native_trigger\n WHERE\n workspace_id = $1\n AND service_name = $2\n AND external_id = $3\n ",
"query": "\n SELECT\n external_id,\n workspace_id,\n service_name AS \"service_name!: ServiceName\",\n script_path,\n is_flow,\n webhook_token_hash,\n service_config,\n error,\n created_at,\n updated_at,\n summary\n FROM\n native_trigger\n WHERE\n workspace_id = $1\n AND service_name = $2\n AND external_id = $3\n ",
"describe": {
"columns": [
{
@@ -62,6 +62,11 @@
"ordinal": 9,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "summary",
"type_info": "Varchar"
}
],
"parameters": {
@@ -91,8 +96,9 @@
true,
true,
false,
false
false,
true
]
},
"hash": "bac545933a627a62b7845d8aab80702443285e4d1d11e5a0f4cd2a3d4add51bb"
"hash": "15014ce696cf2af4f719a537a4e3ca5b322cc130a35a91f8b8854f5ebdf25ad2"
}
@@ -15,7 +15,7 @@
]
},
"nullable": [
null
true
]
},
"hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55"
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n external_id,\n workspace_id,\n service_name AS \"service_name!: ServiceName\",\n script_path,\n is_flow,\n webhook_token_hash,\n service_config,\n error,\n created_at,\n updated_at\n FROM\n native_trigger\n WHERE\n workspace_id = $1\n AND service_name = $2\n AND script_path = $3\n AND is_flow = $4\n LIMIT 1\n ",
"query": "\n SELECT\n external_id,\n workspace_id,\n service_name AS \"service_name!: ServiceName\",\n script_path,\n is_flow,\n webhook_token_hash,\n service_config,\n error,\n created_at,\n updated_at,\n summary\n FROM\n native_trigger\n WHERE\n workspace_id = $1\n AND service_name = $2\n AND script_path = $3\n AND is_flow = $4\n LIMIT 1\n ",
"describe": {
"columns": [
{
@@ -62,6 +62,11 @@
"ordinal": 9,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "summary",
"type_info": "Varchar"
}
],
"parameters": {
@@ -92,8 +97,9 @@
true,
true,
false,
false
false,
true
]
},
"hash": "1a69ef11a3f361f105c2a8af7b7fa182f3953150ade1756259b31a50e9308fce"
"hash": "6dafcc89668fb0e5740f23264b515b1724c36031da39d53ae6c329a479bdf8aa"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false ORDER BY created_at DESC LIMIT 1",
"query": "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false AND archived = false ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
@@ -19,5 +19,5 @@
false
]
},
"hash": "d5661c7557cf3a8dee7cf799cd364d21d38edb827d2c08b0ca7d72311b78d574"
"hash": "a32d7ba43745226fd65328475731526e0b20ea6eeafeb937eb01cdc2cdfcb859"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n nt.external_id,\n nt.workspace_id,\n nt.service_name AS \"service_name!: ServiceName\",\n nt.script_path,\n nt.is_flow,\n nt.webhook_token_hash,\n nt.service_config,\n nt.error,\n nt.created_at,\n nt.updated_at\n FROM\n native_trigger nt\n WHERE\n nt.workspace_id = $1 AND\n nt.service_name = $2 AND\n ($5::text IS NULL OR nt.script_path = $5) AND\n ($6::bool IS NULL OR nt.is_flow = $6) AND\n (\n (nt.is_flow = false AND EXISTS (\n SELECT 1 FROM script s\n WHERE s.workspace_id = nt.workspace_id\n AND s.path = nt.script_path\n ))\n OR\n (nt.is_flow = true AND EXISTS (\n SELECT 1 FROM flow f\n WHERE f.workspace_id = nt.workspace_id\n AND f.path = nt.script_path\n ))\n )\n LIMIT $3\n OFFSET $4\n ",
"query": "\n SELECT\n nt.external_id,\n nt.workspace_id,\n nt.service_name AS \"service_name!: ServiceName\",\n nt.script_path,\n nt.is_flow,\n nt.webhook_token_hash,\n nt.service_config,\n nt.error,\n nt.created_at,\n nt.updated_at,\n nt.summary\n FROM\n native_trigger nt\n WHERE\n nt.workspace_id = $1 AND\n nt.service_name = $2 AND\n ($5::text IS NULL OR nt.script_path = $5) AND\n ($6::bool IS NULL OR nt.is_flow = $6) AND\n (\n (nt.is_flow = false AND EXISTS (\n SELECT 1 FROM script s\n WHERE s.workspace_id = nt.workspace_id\n AND s.path = nt.script_path\n ))\n OR\n (nt.is_flow = true AND EXISTS (\n SELECT 1 FROM flow f\n WHERE f.workspace_id = nt.workspace_id\n AND f.path = nt.script_path\n ))\n )\n LIMIT $3\n OFFSET $4\n ",
"describe": {
"columns": [
{
@@ -62,6 +62,11 @@
"ordinal": 9,
"name": "updated_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "summary",
"type_info": "Varchar"
}
],
"parameters": {
@@ -94,8 +99,9 @@
true,
true,
false,
false
false,
true
]
},
"hash": "a115d8ea786907561afdbbc07d11dc715d80b00c0e79b61b0057a3ae3886a85e"
"hash": "b0775af41a9b54cce040bf37cae770e63dab12a1383a0855d105c061e4e4ca48"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE native_trigger\n SET script_path = $1, is_flow = $2, webhook_token_hash = $3, service_config = $4, error = NULL, updated_at = NOW()\n WHERE\n workspace_id = $5\n AND service_name = $6\n AND external_id = $7\n ",
"query": "\n UPDATE native_trigger\n SET script_path = $1, is_flow = $2, webhook_token_hash = $3, service_config = $4, summary = $8, error = NULL, updated_at = NOW()\n WHERE\n workspace_id = $5\n AND service_name = $6\n AND external_id = $7\n ",
"describe": {
"columns": [],
"parameters": {
@@ -21,10 +21,11 @@
}
}
},
"Text"
"Text",
"Varchar"
]
},
"nullable": []
},
"hash": "40a8bf6a5a42c275d73221bc5f386f2e18cb911352551d0a34bf1933e558674e"
"hash": "bf224f6441c36187f1402f9f01bfe15bb9edfa1dc9052f8a829e486b7334d708"
}
+130 -125
View File
@@ -234,9 +234,9 @@ dependencies = [
[[package]]
name = "arc-swap"
version = "1.8.2"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6"
dependencies = [
"rustversion",
]
@@ -2536,12 +2536,6 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
[[package]]
name = "convert_case"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "convert_case"
version = "0.6.0"
@@ -4887,19 +4881,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "0.99.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
dependencies = [
"convert_case 0.4.0",
"proc-macro2",
"quote",
"rustc_version 0.4.1",
"syn 2.0.117",
]
[[package]]
name = "derive_more"
version = "1.0.0"
@@ -4927,6 +4908,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
"unicode-xid",
]
[[package]]
@@ -7419,13 +7401,13 @@ dependencies = [
[[package]]
name = "ipconfig"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
checksum = "2d72a21f6a71a6c4c3160e095e8925861f5119dd26ef71acee1b9146f74f76c8"
dependencies = [
"socket2 0.5.10",
"socket2 0.6.3",
"widestring",
"windows-sys 0.48.0",
"windows-sys 0.61.2",
"winreg",
]
@@ -7446,9 +7428,9 @@ dependencies = [
[[package]]
name = "iri-string"
version = "0.7.10"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb"
dependencies = [
"memchr",
"serde",
@@ -7538,7 +7520,7 @@ dependencies = [
"cesu8",
"cfg-if",
"combine",
"jni-sys",
"jni-sys 0.3.1",
"log",
"thiserror 1.0.69",
"walkdir",
@@ -7547,9 +7529,31 @@ dependencies = [
[[package]]
name = "jni-sys"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
dependencies = [
"jni-sys 0.4.1",
]
[[package]]
name = "jni-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
dependencies = [
"jni-sys-macros",
]
[[package]]
name = "jni-sys-macros"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
dependencies = [
"quote",
"syn 2.0.117",
]
[[package]]
name = "jobserver"
@@ -8308,9 +8312,9 @@ dependencies = [
[[package]]
name = "malachite"
version = "0.4.18"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a6ecab92657eb234bfe98abd0b17920772c6b14ce69256950142e2eb36d000b"
checksum = "2fbdf9cb251732db30a7200ebb6ae5d22fe8e11397364416617d2c2cf0c51cb5"
dependencies = [
"malachite-base",
"malachite-nz",
@@ -8331,11 +8335,11 @@ dependencies = [
[[package]]
name = "malachite-bigint"
version = "0.2.0"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17703a19c80bbdd0b7919f0f104f3b0597f7de4fc4e90a477c15366a5ba03faa"
checksum = "d149aaa2965d70381709d9df4c7ee1fc0de1c614a4efc2ee356f5e43d68749f8"
dependencies = [
"derive_more 0.99.20",
"derive_more 1.0.0",
"malachite",
"num-integer",
"num-traits",
@@ -8610,9 +8614,9 @@ dependencies = [
[[package]]
name = "moka"
version = "0.12.14"
version = "0.12.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b"
checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
dependencies = [
"async-lock",
"crossbeam-channel",
@@ -8826,7 +8830,7 @@ version = "0.5.0+25.2.9519653"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
dependencies = [
"jni-sys",
"jni-sys 0.3.1",
]
[[package]]
@@ -11663,7 +11667,7 @@ dependencies = [
"once_cell",
"ring 0.17.14",
"rustls-pki-types",
"rustls-webpki 0.103.9",
"rustls-webpki 0.103.10",
"subtle",
"zeroize",
]
@@ -11747,7 +11751,7 @@ dependencies = [
"rustls 0.23.35",
"rustls-native-certs 0.8.3",
"rustls-platform-verifier-android",
"rustls-webpki 0.103.9",
"rustls-webpki 0.103.10",
"security-framework 3.6.0",
"security-framework-sys",
"webpki-root-certs 1.0.6",
@@ -11795,9 +11799,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.103.9"
version = "0.103.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
dependencies = [
"aws-lc-rs",
"ring 0.17.14",
@@ -13877,12 +13881,12 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
dependencies = [
"rustix 1.1.4",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -14468,9 +14472,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.0.10+spec-1.1.0"
version = "1.1.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420"
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011"
dependencies = [
"winnow 1.0.0",
]
@@ -15742,7 +15746,7 @@ dependencies = [
[[package]]
name = "windmill"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-nats",
@@ -15818,7 +15822,7 @@ dependencies = [
[[package]]
name = "windmill-alerting"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -15831,7 +15835,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"argon2",
@@ -15972,7 +15976,7 @@ dependencies = [
[[package]]
name = "windmill-api-agent-workers"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -15995,7 +15999,7 @@ dependencies = [
[[package]]
name = "windmill-api-assets"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16008,7 +16012,7 @@ dependencies = [
[[package]]
name = "windmill-api-auth"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16034,7 +16038,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"reqwest 0.12.28",
"serde",
@@ -16044,7 +16048,7 @@ dependencies = [
[[package]]
name = "windmill-api-configs"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16061,7 +16065,7 @@ dependencies = [
[[package]]
name = "windmill-api-debug"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"base64 0.22.1",
@@ -16084,7 +16088,7 @@ dependencies = [
[[package]]
name = "windmill-api-embeddings"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16107,7 +16111,7 @@ dependencies = [
[[package]]
name = "windmill-api-flow-conversations"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16123,7 +16127,7 @@ dependencies = [
[[package]]
name = "windmill-api-flows"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16143,7 +16147,7 @@ dependencies = [
[[package]]
name = "windmill-api-groups"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16163,7 +16167,7 @@ dependencies = [
[[package]]
name = "windmill-api-inputs"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16177,7 +16181,7 @@ dependencies = [
[[package]]
name = "windmill-api-integration-tests"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-nats",
@@ -16205,7 +16209,7 @@ dependencies = [
[[package]]
name = "windmill-api-jobs"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16230,7 +16234,7 @@ dependencies = [
[[package]]
name = "windmill-api-npm-proxy"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"flate2",
@@ -16248,7 +16252,7 @@ dependencies = [
[[package]]
name = "windmill-api-openapi"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16260,6 +16264,7 @@ dependencies = [
"serde_json",
"serde_yml",
"sqlx",
"tracing",
"url",
"windmill-api-auth",
"windmill-common",
@@ -16269,7 +16274,7 @@ dependencies = [
[[package]]
name = "windmill-api-schedule"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16289,7 +16294,7 @@ dependencies = [
[[package]]
name = "windmill-api-scripts"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16319,7 +16324,7 @@ dependencies = [
[[package]]
name = "windmill-api-settings"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16346,7 +16351,7 @@ dependencies = [
[[package]]
name = "windmill-api-sse"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"lazy_static",
"serde",
@@ -16358,7 +16363,7 @@ dependencies = [
[[package]]
name = "windmill-api-users"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"argon2",
"axum 0.7.9",
@@ -16381,7 +16386,7 @@ dependencies = [
[[package]]
name = "windmill-api-workers"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16395,7 +16400,7 @@ dependencies = [
[[package]]
name = "windmill-api-workspaces"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"axum 0.7.9",
"chrono",
@@ -16426,7 +16431,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"chrono",
"lazy_static",
@@ -16440,7 +16445,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -16459,7 +16464,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"aes-gcm",
"anyhow",
@@ -16559,7 +16564,7 @@ dependencies = [
[[package]]
name = "windmill-dep-map"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"chrono",
"itertools 0.14.0",
@@ -16578,7 +16583,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"regex",
"serde",
@@ -16593,7 +16598,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"astral-tokio-tar",
@@ -16617,7 +16622,7 @@ dependencies = [
[[package]]
name = "windmill-jseval"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"futures",
@@ -16634,7 +16639,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -16650,7 +16655,7 @@ dependencies = [
[[package]]
name = "windmill-mcp"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16671,7 +16676,7 @@ dependencies = [
[[package]]
name = "windmill-native-triggers"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16702,7 +16707,7 @@ dependencies = [
[[package]]
name = "windmill-oauth"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-oauth2",
@@ -16726,7 +16731,7 @@ dependencies = [
[[package]]
name = "windmill-object-store"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-stream",
@@ -16760,7 +16765,7 @@ dependencies = [
[[package]]
name = "windmill-operator"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"futures",
@@ -16778,7 +16783,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -16787,7 +16792,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -16799,7 +16804,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"serde_json",
@@ -16811,7 +16816,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"gosyn",
@@ -16823,7 +16828,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -16835,7 +16840,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"serde_json",
@@ -16847,7 +16852,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"nu-parser",
@@ -16858,7 +16863,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -16869,7 +16874,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -16881,7 +16886,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-asset"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -16892,7 +16897,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -16914,7 +16919,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ruby"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -16928,7 +16933,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -16945,7 +16950,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -16958,7 +16963,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql-asset"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"serde",
@@ -16970,7 +16975,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -16988,7 +16993,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts-asset"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"serde-wasm-bindgen",
@@ -17004,7 +17009,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wac"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17020,7 +17025,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"serde",
@@ -17031,7 +17036,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17068,7 +17073,7 @@ dependencies = [
[[package]]
name = "windmill-runtime-nativets"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"const_format",
@@ -17106,7 +17111,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"getrandom 0.3.4",
"wasm-bindgen",
@@ -17117,7 +17122,7 @@ dependencies = [
[[package]]
name = "windmill-store"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17146,7 +17151,7 @@ dependencies = [
[[package]]
name = "windmill-test-utils"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -17169,7 +17174,7 @@ dependencies = [
[[package]]
name = "windmill-trigger"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17202,7 +17207,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-email"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17222,7 +17227,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-gcp"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17256,7 +17261,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-http"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17291,7 +17296,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-kafka"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17314,7 +17319,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-mqtt"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17338,7 +17343,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-nats"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-nats",
@@ -17362,7 +17367,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-postgres"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17397,7 +17402,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-sqs"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17425,7 +17430,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-websocket"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17448,7 +17453,7 @@ dependencies = [
[[package]]
name = "windmill-types"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"bitflags 2.9.4",
@@ -17467,7 +17472,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"anyhow",
"async-once-cell",
@@ -17574,7 +17579,7 @@ dependencies = [
[[package]]
name = "windmill-worker-volumes"
version = "1.662.0"
version = "1.663.0"
dependencies = [
"bytes",
"futures",
@@ -18189,12 +18194,12 @@ checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
[[package]]
name = "winreg"
version = "0.50.0"
version = "0.55.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.662.0"
version = "1.663.0"
authors.workspace = true
edition.workspace = true
@@ -82,7 +82,7 @@ members = [
exclude = ["./windmill-duckdb-ffi-internal"]
[workspace.package]
version = "1.662.0"
version = "1.663.0"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -0,0 +1 @@
ALTER TABLE native_trigger DROP COLUMN IF EXISTS summary;
@@ -0,0 +1 @@
ALTER TABLE native_trigger ADD COLUMN summary VARCHAR(1000);
@@ -422,6 +422,7 @@ async fn test_delete_integration_full_cascade(db: Pool<Postgres>) -> anyhow::Res
"ext-1",
&trigger_config,
json!({"triggerType": "drive"}),
None,
)
.await?;
@@ -511,6 +512,7 @@ async fn test_cleanup_preserves_triggers(db: Pool<Postgres>) -> anyhow::Result<(
"ext-1",
&trigger_config,
json!({"triggerType": "drive"}),
None,
)
.await?;
+24 -28
View File
@@ -50,11 +50,11 @@ pub fn filter_list_queue_query(
.values
.iter()
.map(|v| {
let p = v.replace("*", "%").replace("'", "''");
let p = v.replace("*", "%");
if w.negated {
format!("v2_job_queue.worker NOT LIKE '{p}'")
format!("v2_job_queue.worker NOT LIKE {}", quote(&p))
} else {
format!("v2_job_queue.worker LIKE '{p}'")
format!("v2_job_queue.worker LIKE {}", quote(&p))
}
})
.collect();
@@ -77,11 +77,11 @@ pub fn filter_list_queue_query(
.values
.iter()
.map(|v| {
let e = v.replace("'", "''");
let p = format!("{}%", v);
if ps.negated {
format!("runnable_path NOT LIKE '{e}%'")
format!("runnable_path NOT LIKE {}", quote(&p))
} else {
format!("runnable_path LIKE '{e}%'")
format!("runnable_path LIKE {}", quote(&p))
}
})
.collect();
@@ -123,11 +123,11 @@ pub fn filter_list_queue_query(
.values
.iter()
.map(|v| {
let p = v.replace("*", "%").replace("'", "''");
let p = v.replace("*", "%");
if t.negated {
format!("v2_job.tag NOT LIKE '{p}'")
format!("v2_job.tag NOT LIKE {}", quote(&p))
} else {
format!("v2_job.tag LIKE '{p}'")
format!("v2_job.tag LIKE {}", quote(&p))
}
})
.collect();
@@ -287,14 +287,14 @@ pub fn filter_list_completed_query(
.values
.iter()
.map(|v| {
let p = v.replace("*", "%").replace("'", "''");
let p = v.replace("*", "%");
if label.negated {
format!(
"NOT EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') lbl WHERE jsonb_typeof(result->'wm_labels') = 'array' AND lbl LIKE '{p}')"
"NOT EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') lbl WHERE jsonb_typeof(result->'wm_labels') = 'array' AND lbl LIKE {})", quote(&p)
)
} else {
format!(
"EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') lbl WHERE jsonb_typeof(result->'wm_labels') = 'array' AND lbl LIKE '{p}')"
"EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') lbl WHERE jsonb_typeof(result->'wm_labels') = 'array' AND lbl LIKE {})", quote(&p)
)
}
})
@@ -308,14 +308,14 @@ pub fn filter_list_completed_query(
let clauses: Vec<_> = label
.values
.iter()
.map(|v| format!("NOT (result->'wm_labels' ? '{}')", v.replace("'", "''")))
.map(|v| format!("NOT (result->'wm_labels' ? {})", quote(v)))
.collect();
sqlb.and_where(format!("({})", clauses.join(" AND ")));
} else {
let clauses: Vec<_> = label
.values
.iter()
.map(|v| format!("result->'wm_labels' ? '{}'", v.replace("'", "''")))
.map(|v| format!("result->'wm_labels' ? {}", quote(v)))
.collect();
sqlb.and_where("result ? 'wm_labels'");
sqlb.and_where(format!("({})", clauses.join(" OR ")));
@@ -329,11 +329,11 @@ pub fn filter_list_completed_query(
.values
.iter()
.map(|v| {
let p = v.replace("*", "%").replace("'", "''");
let p = v.replace("*", "%");
if worker.negated {
format!("v2_job_completed.worker NOT LIKE '{p}'")
format!("v2_job_completed.worker NOT LIKE {}", quote(&p))
} else {
format!("v2_job_completed.worker LIKE '{p}'")
format!("v2_job_completed.worker LIKE {}", quote(&p))
}
})
.collect();
@@ -366,11 +366,11 @@ pub fn filter_list_completed_query(
.values
.iter()
.map(|v| {
let e = v.replace("'", "''");
let p = format!("{}%", v);
if ps.negated {
format!("runnable_path NOT LIKE '{e}%'")
format!("runnable_path NOT LIKE {}", quote(&p))
} else {
format!("runnable_path LIKE '{e}%'")
format!("runnable_path LIKE {}", quote(&p))
}
})
.collect();
@@ -400,11 +400,11 @@ pub fn filter_list_completed_query(
.values
.iter()
.map(|v| {
let p = v.replace("*", "%").replace("'", "''");
let p = v.replace("*", "%");
if t.negated {
format!("v2_job.tag NOT LIKE '{p}'")
format!("v2_job.tag NOT LIKE {}", quote(&p))
} else {
format!("v2_job.tag LIKE '{p}'")
format!("v2_job.tag LIKE {}", quote(&p))
}
})
.collect();
@@ -449,11 +449,7 @@ pub fn filter_list_completed_query(
}
if let Some(dt) = &lq.created_or_started_after {
let ts = dt.to_rfc3339();
sqlb.and_where(format!(
"(created_at >= '{}' OR started_at >= '{}')",
ts.replace("'", "''"),
ts.replace("'", "''")
));
sqlb.and_where("(created_at >= ? OR started_at >= ?)".bind(&ts).bind(&ts));
}
if let Some(dt) = &lq.created_before {
+13 -1
View File
@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.662.0
version: 1.663.0
title: Windmill API
contact:
@@ -24592,6 +24592,10 @@ components:
type: string
nullable: true
description: Error message if the trigger is in an error state
summary:
type: string
nullable: true
description: Short summary to be displayed when listed
required:
- external_id
- workspace_id
@@ -24626,6 +24630,10 @@ components:
type: string
nullable: true
description: Error message if the trigger is in an error state
summary:
type: string
nullable: true
description: Short summary to be displayed when listed
external_data:
type: object
description: Configuration data from the external service
@@ -24718,6 +24726,10 @@ components:
type: object
description: Service-specific configuration (e.g., event types, filters)
additionalProperties: true
summary:
type: string
nullable: true
description: Short summary to be displayed when listed
required:
- script_path
- is_flow
+1 -4
View File
@@ -2027,10 +2027,7 @@ async fn count_completed_jobs_detail(
if let Some(tags) = query.tags {
sqlb.and_where_in(
"v2_job.tag",
&tags
.split(",")
.map(|t| format!("'{}'", t))
.collect::<Vec<_>>(),
&tags.split(",").map(|t| quote(t)).collect::<Vec<_>>(),
);
}
@@ -68,7 +68,7 @@ pub async fn trigger_dependents_to_recompute_dependencies(
let job_payload = match importer_kind.as_str() {
"script" => match sqlx::query_scalar!(
"SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false ORDER BY created_at DESC LIMIT 1",
"SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false AND archived = false ORDER BY created_at DESC LIMIT 1",
importer_path,
w_id
)
@@ -181,6 +181,7 @@ async fn create_native_trigger<T: External>(
&external_id,
&config,
service_config,
data.summary.as_deref(),
)
.await?;
@@ -304,6 +305,7 @@ async fn update_native_trigger_handler<T: External>(
&external_id,
&config,
service_config,
data.summary.as_deref(),
)
.await?;
+17 -7
View File
@@ -195,6 +195,7 @@ pub struct NativeTrigger {
pub error: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub summary: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -209,6 +210,7 @@ pub struct NativeTriggerData<C> {
pub script_path: String,
pub is_flow: bool,
pub service_config: C,
pub summary: Option<String>,
}
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
@@ -821,6 +823,7 @@ pub async fn store_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres>
external_id: &str,
config: &NativeTriggerConfig,
service_config: C,
summary: Option<&str>,
) -> Result<()> {
use windmill_common::auth::hash_token;
@@ -835,12 +838,13 @@ pub async fn store_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres>
script_path,
is_flow,
webhook_token_hash,
service_config
service_config,
summary
) VALUES (
$1, $2, $3, $4, $5, $6, $7
$1, $2, $3, $4, $5, $6, $7, $8
)
ON CONFLICT (external_id, workspace_id, service_name)
DO UPDATE SET script_path = $4, is_flow = $5, webhook_token_hash = $6, service_config = $7, error = NULL, updated_at = NOW()
DO UPDATE SET script_path = $4, is_flow = $5, webhook_token_hash = $6, service_config = $7, summary = $8, error = NULL, updated_at = NOW()
"#,
external_id,
workspace_id,
@@ -849,6 +853,7 @@ pub async fn store_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres>
config.is_flow,
webhook_token_hash,
sqlx::types::Json(service_config) as _,
summary,
)
.execute(db)
.await?;
@@ -863,6 +868,7 @@ pub async fn update_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres
external_id: &str,
config: &NativeTriggerConfig,
service_config: Option<&RawValue>,
summary: Option<&str>,
) -> Result<()> {
use windmill_common::auth::hash_token;
@@ -871,7 +877,7 @@ pub async fn update_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres
sqlx::query!(
r#"
UPDATE native_trigger
SET script_path = $1, is_flow = $2, webhook_token_hash = $3, service_config = $4, error = NULL, updated_at = NOW()
SET script_path = $1, is_flow = $2, webhook_token_hash = $3, service_config = $4, summary = $8, error = NULL, updated_at = NOW()
WHERE
workspace_id = $5
AND service_name = $6
@@ -884,6 +890,7 @@ pub async fn update_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres
workspace_id,
service_name as ServiceName,
external_id,
summary,
)
.execute(db)
.await?;
@@ -934,7 +941,8 @@ pub async fn get_native_trigger<'c, E: sqlx::Executor<'c, Database = Postgres>>(
service_config,
error,
created_at,
updated_at
updated_at,
summary
FROM
native_trigger
WHERE
@@ -972,7 +980,8 @@ pub async fn get_native_trigger_by_script<'c, E: sqlx::Executor<'c, Database = P
service_config,
error,
created_at,
updated_at
updated_at,
summary
FROM
native_trigger
WHERE
@@ -1018,7 +1027,8 @@ pub async fn list_native_triggers<'c, E: sqlx::Executor<'c, Database = Postgres>
nt.service_config,
nt.error,
nt.created_at,
nt.updated_at
nt.updated_at,
nt.summary
FROM
native_trigger nt
WHERE
+3 -12
View File
@@ -133,21 +133,12 @@ async fn list_variables(
])
.left()
.join("account")
.on(&format!(
"variable.account = account.id AND account.workspace_id = '{}'",
w_id
))
.on("variable.account = account.id AND account.workspace_id = ?".bind(&w_id))
.left()
.join("resource")
.on(&format!(
"resource.path = variable.path AND resource.workspace_id = '{}'",
w_id
))
.on("resource.path = variable.path AND resource.workspace_id = ?".bind(&w_id))
.and_where("variable.workspace_id = ?".bind(&w_id))
.and_where(&format!(
"variable.path NOT LIKE 'u/' || '{}' || '/secret_arg/%'",
authed.username
))
.and_where("variable.path NOT LIKE 'u/' || ? || '/secret_arg/%'".bind(&authed.username))
.order_by("path", false)
.limit(per_page)
.offset(offset)
+1 -1
View File
@@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts";
import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts";
import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts";
export const VERSION = "v1.662.0";
export const VERSION = "v1.663.0";
export async function login(email: string, password: string): Promise<string> {
return await windmill.UserService.login({
+4
View File
@@ -231,6 +231,7 @@ export async function pushNativeTrigger(
is_flow: result.is_flow,
service_config: result.service_config,
error: result.error,
summary: result.summary,
};
log.debug(`Native trigger ${serviceName}/${externalId} exists on remote`);
} catch {
@@ -243,6 +244,7 @@ export async function pushNativeTrigger(
script_path: localTrigger.script_path,
is_flow: localTrigger.is_flow,
service_config: localTrigger.service_config,
summary: localTrigger.summary,
};
if (remoteTrigger) {
@@ -251,11 +253,13 @@ export async function pushNativeTrigger(
script_path: localTrigger.script_path,
is_flow: localTrigger.is_flow,
service_config: localTrigger.service_config,
summary: localTrigger.summary,
};
const remoteCompare = {
script_path: remoteTrigger.script_path,
is_flow: remoteTrigger.is_flow,
service_config: remoteTrigger.service_config,
summary: remoteTrigger.summary,
};
if (isSuperset(localCompare, remoteCompare)) {
+1 -1
View File
@@ -68,7 +68,7 @@ export {
workspaceAdd,
};
export const VERSION = "1.662.0";
export const VERSION = "1.663.0";
// Re-exported from constants.ts to maintain backwards compatibility
export { WM_FORK_PREFIX } from "./core/constants.ts";
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "windmill-components",
"version": "1.662.0",
"version": "1.663.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "windmill-components",
"version": "1.662.0",
"version": "1.663.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "windmill-components",
"version": "1.662.0",
"version": "1.663.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",
@@ -170,7 +170,9 @@ export async function saveScheduleFromCfg(
tag: scheduleCfg.tag,
paused_until: scheduleCfg.paused_until,
cron_version: scheduleCfg.cron_version,
dynamic_skip: scheduleCfg.dynamic_skip
dynamic_skip: scheduleCfg.dynamic_skip,
permissioned_as: scheduleCfg.permissioned_as,
preserve_permissioned_as: scheduleCfg.preserve_permissioned_as
}
try {
if (edit) {
@@ -0,0 +1,84 @@
<script lang="ts">
import OnBehalfOfSelector, {
type OnBehalfOfChoice,
type OnBehalfOfDetails
} from '$lib/components/OnBehalfOfSelector.svelte'
import { userStore, workspaceStore } from '$lib/stores'
import { AlertTriangle } from 'lucide-svelte'
interface Props {
/** Current permissioned_as value from the trigger (e.g., 'u/admin') */
permissionedAs: string | undefined
/** Callback when user changes the permissioned_as selection */
onPermissionedAsChange: (permissionedAs: string | undefined, preserve: boolean) => void
}
let { permissionedAs, onPermissionedAsChange }: Props = $props()
const canPreserve = $derived(
$userStore?.is_admin || ($userStore?.groups ?? []).includes('wm_deployers')
)
const myPermissionedAs = $derived($userStore?.username ? `u/${$userStore.username}` : undefined)
let onBehalfOfChoice = $state<OnBehalfOfChoice>(undefined)
let customPermissionedAs = $state<string | undefined>(undefined)
const effectivePermissionedAs = $derived.by(() => {
if (onBehalfOfChoice === 'target') return permissionedAs
if (onBehalfOfChoice === 'custom' && customPermissionedAs) return customPermissionedAs
return myPermissionedAs
})
const willChange = $derived(
permissionedAs !== undefined &&
effectivePermissionedAs !== undefined &&
permissionedAs !== effectivePermissionedAs
)
function handleSelect(choice: OnBehalfOfChoice, details?: OnBehalfOfDetails) {
onBehalfOfChoice = choice
if (choice === 'target') {
customPermissionedAs = undefined
onPermissionedAsChange(permissionedAs, true)
} else if (choice === 'custom' && details) {
customPermissionedAs = details.permissionedAs
onPermissionedAsChange(details.permissionedAs, true)
} else {
customPermissionedAs = undefined
onPermissionedAsChange(undefined, false)
}
}
</script>
{#if permissionedAs && $workspaceStore}
<div class="flex items-center gap-1.5 text-2xs text-tertiary mb-4">
<span>Permissioned as</span>
{#if canPreserve}
<OnBehalfOfSelector
targetWorkspace={$workspaceStore}
targetValue={permissionedAs}
selected={onBehalfOfChoice}
onSelect={handleSelect}
kind="trigger"
{canPreserve}
customValue={customPermissionedAs}
isDeployment={false}
/>
{#if willChange}
<AlertTriangle class="w-3.5 h-3.5 text-yellow-500" />
<span class="text-yellow-600 dark:text-yellow-400"
>will change from <strong>{permissionedAs}</strong> on save</span
>
{/if}
{:else}
<strong class="text-secondary">{permissionedAs}</strong>
{#if willChange}
<AlertTriangle class="w-3.5 h-3.5 text-yellow-500" />
<span class="text-yellow-600 dark:text-yellow-400"
>will change to <strong>{effectivePermissionedAs}</strong> on save</span
>
{/if}
{/if}
</div>
{/if}
@@ -118,7 +118,7 @@
{trigger?.isDraft ? 'Deploy' : 'Update'}
</Button>
{#snippet text()}
<span >
<span>
{#if !isDeployed}
Deploy the runnable to enable trigger creation
{:else if cloudDisabled}
@@ -127,7 +127,7 @@
Enter a valid config to {trigger?.isDraft ? 'deploy' : 'update'} the trigger
{/if}
</span>
{/snippet}
{/snippet}
</Tooltip>
{/if}
</div>
@@ -20,6 +20,7 @@
import Label from '$lib/components/Label.svelte'
import EmailTriggerEditorConfigSection from './EmailTriggerEditorConfigSection.svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { getHandlerType, handleConfigChange } from '../utils'
import { untrack } from 'svelte'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
@@ -75,6 +76,9 @@
let drawer = $state<Drawer | undefined>(undefined)
let initialConfig: NewEmailTrigger | undefined = undefined
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let optionTabSelected: 'error_handler' | 'retries' = $state('error_handler')
let errorHandlerSelected: ErrorHandler = $state('slack')
@@ -181,6 +185,9 @@
retry = cfg?.retry
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
mode = cfg?.mode ?? 'enabled'
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
async function loadTrigger(defaultConfig?: Partial<EmailTrigger>): Promise<void> {
@@ -236,7 +243,9 @@
error_handler_path,
error_handler_args,
retry,
mode
mode,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
return nCfg
@@ -304,6 +313,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-12">
{#if mode === 'suspended'}
<TriggerSuspendedJobsAlert {suspendedJobsModal} />
@@ -30,7 +30,9 @@ export async function saveEmailTriggerFromCfg(
error_handler_path: emailCfg.error_handler_path,
error_handler_args: emailCfg.error_handler_path ? emailCfg.error_handler_args : undefined,
mode: emailCfg.mode,
retry: emailCfg.retry
retry: emailCfg.retry,
permissioned_as: emailCfg.permissioned_as,
preserve_permissioned_as: emailCfg.preserve_permissioned_as
}
try {
if (edit) {
@@ -22,6 +22,7 @@
import GcpTriggerEditorConfigSection from './GcpTriggerEditorConfigSection.svelte'
import { untrack, type Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { saveGcpTriggerFromCfg } from './utils'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import { deepEqual } from 'fast-equals'
@@ -57,6 +58,9 @@
let subscription_mode: SubscriptionMode = $state('create_update')
let initialConfig: Record<string, any> | undefined = undefined
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let base_endpoint = $derived(`${window.location.origin}${base}`)
let auto_acknowledge_msg = $state(true)
let ack_deadline: number | undefined = $state()
@@ -202,6 +206,9 @@
auto_acknowledge_msg = cfg?.auto_acknowledge_msg ?? true
ack_deadline = cfg?.ack_deadline
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
async function updateTrigger(): Promise<void> {
@@ -246,7 +253,9 @@
error_handler_args,
retry,
auto_acknowledge_msg,
ack_deadline
ack_deadline,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -369,6 +378,15 @@
<p>Loading...</p>
</div>
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-5">
{#if mode === 'suspended'}
<TriggerSuspendedJobsAlert {suspendedJobsModal} />
@@ -454,9 +472,11 @@
<Section label="Advanced" collapsable>
{#snippet header()}
<TriggerAdvancedBadges {error_handler_path} {retry} extraBadges={[
{ name: 'Manual Ack', active: !auto_acknowledge_msg }
]} />
<TriggerAdvancedBadges
{error_handler_path}
{retry}
extraBadges={[{ name: 'Manual Ack', active: !auto_acknowledge_msg }]}
/>
{/snippet}
<div class="flex flex-col gap-6">
<div class="min-h-96">
@@ -32,6 +32,8 @@ export async function saveGcpTriggerFromCfg(
is_flow: cfg.is_flow,
auto_acknowledge_msg: cfg.auto_acknowledge_msg,
ack_deadline: cfg.ack_deadline,
permissioned_as: cfg.permissioned_as,
preserve_permissioned_as: cfg.preserve_permissioned_as,
...errorHandlerAndRetries
}
if (edit) {
@@ -46,6 +46,7 @@
import RouteBodyTransformerOption from './RouteBodyTransformerOption.svelte'
import TestingBadge from '../testingBadge.svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { getHandlerType, handleConfigChange } from '../utils'
import autosize from '$lib/autosize'
import { untrack } from 'svelte'
@@ -122,6 +123,9 @@
let drawer = $state<Drawer | undefined>(undefined)
let initialConfig: NewHttpTrigger | undefined = undefined
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let optionTabSelected: 'request_options' | 'error_handler' | 'retries' = $state('request_options')
let errorHandlerSelected: ErrorHandler = $state('slack')
@@ -315,6 +319,9 @@
error_handler_args = cfg?.error_handler_args ?? {}
retry = cfg?.retry
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
async function loadTrigger(defaultConfig?: Partial<HttpTrigger>): Promise<void> {
@@ -388,7 +395,9 @@
description: routeDescription,
error_handler_path,
error_handler_args,
retry
retry,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
return nCfg
@@ -481,6 +490,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-8">
{#if mode === 'suspended'}
<TriggerSuspendedJobsAlert {suspendedJobsModal} />
@@ -697,11 +715,15 @@
{#if !is_static_website}
<Section label="Advanced" collapsable>
{#snippet header()}
<TriggerAdvancedBadges {error_handler_path} {retry} extraBadges={[
{ name: 'Async', active: request_type === 'async' },
{ name: 'SSE', active: request_type === 'sync_sse' },
{ name: 'Authentication', active: authentication_method !== 'none' }
]} />
<TriggerAdvancedBadges
{error_handler_path}
{retry}
extraBadges={[
{ name: 'Async', active: request_type === 'async' },
{ name: 'SSE', active: request_type === 'sync_sse' },
{ name: 'Authentication', active: authentication_method !== 'none' }
]}
/>
{/snippet}
<div class="min-h-96">
<Tabs bind:selected={optionTabSelected}>
@@ -61,7 +61,9 @@ export async function saveHttpRouteFromCfg(
error_handler_path: routeCfg.error_handler_path,
error_handler_args: routeCfg.error_handler_path ? routeCfg.error_handler_args : undefined,
retry: routeCfg.retry,
mode: routeCfg.mode
mode: routeCfg.mode,
permissioned_as: routeCfg.permissioned_as,
preserve_permissioned_as: routeCfg.preserve_permissioned_as
}
try {
if (edit) {
@@ -15,6 +15,7 @@
import KafkaTriggersConfigSection from './KafkaTriggersConfigSection.svelte'
import { untrack, type Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { saveKafkaTriggerFromCfg } from './utils'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
@@ -87,6 +88,9 @@
let autoOffsetReset = $state('latest')
let autoCommit = $state(true)
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let resetLoading = $state(false)
let optionTabSelected: 'error_handler' | 'retries' = $state('error_handler')
let errorHandlerSelected: ErrorHandler = $state('slack')
@@ -216,6 +220,9 @@
retry = cfg?.retry
filters = cfg?.filters ?? []
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
async function loadTrigger(defaultConfig?: Record<string, any>): Promise<void> {
@@ -246,7 +253,9 @@
extra_perms: extra_perms,
error_handler_path,
error_handler_args,
retry
retry,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -414,6 +423,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-4">
{#if description}
{@render description()}
@@ -531,11 +549,10 @@
Offsets will not be committed automatically. Use <code
>wmill.commit_kafka_offsets(trigger_path, topic, partition, offset)</code
>
in Python or <code
>wmill.commitKafkaOffsets(triggerPath, topic, partition, offset)</code
> in TypeScript with the values from the event payload. The consumer collects
all pending commits and commits the highest offset for each topic/partition
pair.
in Python or
<code>wmill.commitKafkaOffsets(triggerPath, topic, partition, offset)</code> in TypeScript
with the values from the event payload. The consumer collects all pending commits and
commits the highest offset for each topic/partition pair.
</Alert>
{/if}
</div>
@@ -26,7 +26,9 @@ export async function saveKafkaTriggerFromCfg(
filters: cfg.filters ?? [],
auto_offset_reset: cfg.auto_offset_reset ?? 'latest',
auto_commit: cfg.auto_commit ?? true,
...errorHandlerAndRetries
...errorHandlerAndRetries,
permissioned_as: cfg.permissioned_as,
preserve_permissioned_as: cfg.preserve_permissioned_as
}
try {
if (edit) {
@@ -24,6 +24,7 @@
import MqttEditorConfigSection from './MqttEditorConfigSection.svelte'
import type { Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { saveMqttTriggerFromCfg } from './utils'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
@@ -98,6 +99,9 @@
let isValid: boolean = $state(false)
let initialConfig: Record<string, any> | undefined = {}
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let errorHandlerSelected: ErrorHandler = $state('slack')
let error_handler_path: string | undefined = $state()
let error_handler_args: Record<string, any> = $state({})
@@ -215,6 +219,9 @@
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
activateV5Options.topic_alias_maximum = Boolean(v5_config.topic_alias_maximum)
activateV5Options.session_expiry_interval = Boolean(v5_config.session_expiry_interval)
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
} catch (error) {
sendUserToast(`Could not load mqtt trigger config: ${error.body}`, true)
}
@@ -251,7 +258,9 @@
is_flow,
error_handler_path,
error_handler_args,
retry
retry,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -392,6 +401,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-4">
{#if description}
{@render description()}
@@ -471,10 +489,14 @@
<Section label="Advanced" collapsable>
{#snippet header()}
<TriggerAdvancedBadges {error_handler_path} {retry} extraBadges={[
{ name: 'Custom Client ID', active: !!client_id },
{ name: 'MQTT v3', active: client_version === 'v3' }
]} />
<TriggerAdvancedBadges
{error_handler_path}
{retry}
extraBadges={[
{ name: 'Custom Client ID', active: !!client_id },
{ name: 'MQTT v3', active: client_version === 'v3' }
]}
/>
{/snippet}
<div class="flex flex-col gap-6">
<div class="min-h-96">
@@ -27,6 +27,8 @@ export async function saveMqttTriggerFromCfg(
script_path: cfg.script_path,
is_flow: cfg.is_flow,
mode: cfg.mode,
permissioned_as: cfg.permissioned_as,
preserve_permissioned_as: cfg.preserve_permissioned_as,
...errorHandlerAndRetries
}
try {
@@ -11,6 +11,7 @@
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, emptyString, sendUserToast } from '$lib/utils'
import { Button } from '$lib/components/common'
import TextInput from '$lib/components/text_input/TextInput.svelte'
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
import DrawerContent from '$lib/components/common/drawer/DrawerContent.svelte'
import { Loader2, Save } from 'lucide-svelte'
@@ -94,6 +95,7 @@
let initialScriptPath = $state('')
let fixedScriptPath = $state('')
let isFlow = $state(false)
let summary = $state('')
let externalId = $state<string | null>(null)
let can_write = $state(true)
let originalConfig = $state<Record<string, any> | undefined>(undefined)
@@ -123,6 +125,7 @@
can_write = true
originalConfig = undefined
initialConfig = undefined
summary = ''
}
export function openRecreate(nativeTrigger: ExtendedNativeTrigger) {
@@ -146,6 +149,7 @@
can_write = true
originalConfig = undefined
initialConfig = undefined
summary = nativeTrigger.summary ?? ''
}
export async function openEdit(
@@ -182,6 +186,7 @@
scriptPath = fullTrigger.script_path
initialScriptPath = fullTrigger.script_path
can_write = canWrite(fullTrigger.script_path, {}, $userStore)
summary = fullTrigger.summary ?? ''
externalData = fullTrigger.external_data
// Apply default values if provided (for draft triggers)
@@ -203,7 +208,8 @@
return {
script_path: scriptPath,
is_flow: isFlow,
service_config: serviceConfig
service_config: serviceConfig,
summary: summary !== '' ? summary : undefined
}
}
@@ -386,6 +392,22 @@
{/if}
</div>
<div class="flex flex-col gap-12 mt-6">
<Section label="Metadata">
<div class="flex flex-col gap-6">
<label class="flex flex-col gap-1">
<span class="text-xs font-semibold text-emphasis">Summary</span>
<TextInput
inputProps={{
type: 'text',
placeholder: 'Short summary to be displayed when listed',
disabled: !can_write
}}
bind:value={summary}
/>
</label>
</div>
</Section>
{#if !hideTarget}
<Section label="Runnable">
<p class="text-xs mb-1 text-primary">
@@ -98,20 +98,31 @@
{@html trigger.marked}
</span>
{:else}
{trigger.script_path}
{trigger.summary || trigger.script_path}
{/if}
</div>
{#if trigger.summary}
<div class="text-secondary text-xs truncate text-left font-normal">
{trigger.script_path}
</div>
{/if}
{#if service === 'google'}
{@const triggerType = trigger.service_config?.triggerType}
{@const resourceName = trigger.service_config?.resourceName}
{@const calendarName = trigger.service_config?.calendarName}
<div class="text-secondary text-xs truncate text-left font-normal flex items-center gap-1 mb-0.5">
<div
class="text-secondary text-xs truncate text-left font-normal flex items-center gap-1 mb-0.5"
>
{#if triggerType === 'calendar'}
<GoogleCalendarIcon height="12px" width="12px" />
Calendar: {calendarName || trigger.service_config?.calendarId || ''}
{:else}
<GoogleDriveIcon height="12px" width="12px" />
Drive: {resourceName ? resourceName : trigger.service_config?.resourceId ? trigger.service_config.resourceId : 'All changes'}
Drive: {resourceName
? resourceName
: trigger.service_config?.resourceId
? trigger.service_config.resourceId
: 'All changes'}
{/if}
</div>
{/if}
@@ -111,7 +111,7 @@ export function validateCommonFields(config: Record<string, any>): Record<string
}
export function formatTriggerDisplayName(trigger: NativeTrigger): string {
return `${trigger.script_path} (external id: ${trigger.external_id})`
return `${trigger.summary ?? ''} ${trigger.script_path} (external id: ${trigger.external_id})`
}
export function getTriggerIconName(service: NativeServiceName): string {
@@ -199,7 +199,8 @@ export async function saveNativeTriggerFromCfg(
const requestBody: NativeTriggerData = {
script_path: triggerCfg.script_path,
is_flow: triggerCfg.is_flow,
service_config: triggerCfg.service_config
service_config: triggerCfg.service_config,
summary: triggerCfg.summary
}
const serviceName = NATIVE_TRIGGER_SERVICES[service].serviceDisplayName
@@ -14,6 +14,7 @@
import NatsTriggersConfigSection from './NatsTriggersConfigSection.svelte'
import { untrack, type Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { saveNatsTriggerFromCfg } from './utils'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
@@ -89,6 +90,9 @@
use_jetstream: false
})
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let isValid = $state(false)
let optionTabSelected: 'error_handler' | 'retries' = $state('error_handler')
let errorHandlerSelected: ErrorHandler = $state('slack')
@@ -201,6 +205,9 @@
error_handler_args = cfg?.error_handler_args ?? {}
retry = cfg?.retry
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
async function loadTrigger(defaultConfig?: Record<string, any>): Promise<void> {
@@ -229,7 +236,9 @@
use_jetstream: natsCfg.use_jetstream,
error_handler_path,
error_handler_args,
retry
retry,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -376,6 +385,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-4">
{#if description}
{@render description()}
@@ -25,6 +25,8 @@ export async function saveNatsTriggerFromCfg(
consumer_name: cfg.consumer_name,
subjects: cfg.subjects,
use_jetstream: cfg.use_jetstream,
permissioned_as: cfg.permissioned_as,
preserve_permissioned_as: cfg.preserve_permissioned_as,
...errorHandlerAndRetries
}
try {
@@ -33,6 +33,7 @@
import { base } from '$lib/base'
import { untrack, type Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import TestingBadge from '../testingBadge.svelte'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import TriggerRetriesAndErrorHandler from '../TriggerRetriesAndErrorHandler.svelte'
@@ -113,6 +114,9 @@
let basic_mode = $derived(tab === 'basic')
let initialConfig: Record<string, any> | undefined = undefined
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let creatingSlot: boolean = $state(false)
let creatingPublication: boolean = $state(false)
let pg14: boolean = $derived(postgresVersion.startsWith('14'))
@@ -318,7 +322,9 @@
error_handler_path,
error_handler_args,
retry,
mode
mode,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
return cfg
}
@@ -339,6 +345,9 @@
retry = cfg?.retry
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
mode = cfg?.mode ?? 'enabled'
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
async function loadTrigger(defaultConfig?: Record<string, any>): Promise<void> {
@@ -553,6 +562,15 @@
</div>
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-4">
{#if description}
{@render description()}
@@ -126,6 +126,8 @@ export async function savePostgresTriggerFromCfg(
publication_name: config.publication_name,
publication: config.publication,
mode: config.mode,
permissioned_as: config.permissioned_as,
preserve_permissioned_as: config.preserve_permissioned_as,
...errorHandlerAndRetries
}
if (edit) {
@@ -38,6 +38,7 @@
import { handleConfigChange } from '../utils'
import TextInput from '$lib/components/text_input/TextInput.svelte'
import { twMerge } from 'tailwind-merge'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
let {
useDrawer = true,
@@ -111,6 +112,9 @@
let isValid = $state(true)
let allowSchedule = $derived(isValid && validCRON && script_path != '')
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
const saveDisabled = $derived(
!allowSchedule ||
@@ -507,6 +511,9 @@
extraPerms = cfg.extra_perms ?? {}
can_write = canWrite(cfg.path, cfg.extra_perms, $userStore)
tag = cfg.tag
permissionedAs = cfg.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
loading = false
}
@@ -605,7 +612,9 @@
paused_until: paused_until,
cron_version: cronVersion,
extra_perms: extraPerms,
dynamic_skip: dynamicSkipPath
dynamic_skip: dynamicSkipPath,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -682,6 +691,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-8">
<Section label="Metadata">
<div class="flex flex-col gap-6">
@@ -913,12 +931,16 @@
<Section label="Advanced" collapsable>
{#snippet header()}
<TriggerAdvancedBadges error_handler_path={errorHandlerPath} {retry} extraBadges={[
{ name: 'Recovery Handler', active: !!recoveryHandlerPath },
{ name: 'Success Handler', active: !!successHandlerPath },
{ name: 'Dynamic Skip', active: !!dynamicSkipPath },
{ name: 'Custom Tag', active: !!tag }
]} />
<TriggerAdvancedBadges
error_handler_path={errorHandlerPath}
{retry}
extraBadges={[
{ name: 'Recovery Handler', active: !!recoveryHandlerPath },
{ name: 'Success Handler', active: !!successHandlerPath },
{ name: 'Dynamic Skip', active: !!dynamicSkipPath },
{ name: 'Custom Tag', active: !!tag }
]}
/>
{/snippet}
{@render errorHandler()}
</Section>
@@ -20,6 +20,7 @@
import Required from '$lib/components/Required.svelte'
import { untrack, type Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { saveSqsTriggerFromCfg } from './utils'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
@@ -88,6 +89,9 @@
let isValid = $state(false)
let initialConfig: Record<string, any> | undefined = undefined
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let optionTabSelected: 'error_handler' | 'retries' = $state('error_handler')
let errorHandlerSelected: ErrorHandler = $state('slack')
let error_handler_path: string | undefined = $state()
@@ -189,6 +193,9 @@
error_handler_args = cfg?.error_handler_args ?? {}
retry = cfg?.retry
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
} catch (error) {
sendUserToast(`Could not load SQS trigger config: ${error.body}`, true)
}
@@ -223,7 +230,9 @@
mode,
error_handler_path,
error_handler_args,
retry
retry,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -362,6 +371,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-4">
{#if description}
{@render description()}
@@ -25,6 +25,8 @@ export async function saveSqsTriggerFromCfg(
message_attributes: cfg.message_attributes,
aws_auth_resource_type: cfg.aws_auth_resource_type,
mode: cfg.mode,
permissioned_as: cfg.permissioned_as,
preserve_permissioned_as: cfg.preserve_permissioned_as,
...errorHandlerAndRetries
}
try {
@@ -481,14 +481,15 @@ export function getLightConfig(
} else if (triggerType === 'email') {
return { local_part: trigger.local_part }
} else if (triggerType === 'nextcloud') {
return { event: trigger.service_config?.event ?? trigger.event }
return { event: trigger.service_config?.event ?? trigger.event, summary: trigger.summary }
} else if (triggerType === 'google') {
return {
trigger_type: trigger.service_config?.triggerType ?? trigger.trigger_type,
resource_id: trigger.service_config?.resourceId ?? trigger.resource_id,
resource_name: trigger.service_config?.resourceName ?? trigger.resource_name,
calendar_id: trigger.service_config?.calendarId ?? trigger.calendar_id,
calendar_name: trigger.service_config?.calendarName ?? trigger.calendar_name
calendar_name: trigger.service_config?.calendarName ?? trigger.calendar_name,
summary: trigger.summary
}
} else {
return undefined
@@ -524,8 +525,12 @@ export function getTriggerLabel(trigger: Trigger): string {
return `${config?.url}`
} else if (type === 'email' && config?.local_part) {
return `${config?.local_part}`
} else if (type === 'nextcloud' && config?.summary) {
return `${config.summary}`
} else if (type === 'nextcloud' && path) {
return `${path}`
} else if (type === 'google' && config?.summary) {
return `${config.summary}`
} else if (type === 'google' && path) {
const triggerType = config?.trigger_type ?? config?.triggerType
if (triggerType === 'calendar') {
@@ -31,6 +31,7 @@
import { untrack, type Snippet } from 'svelte'
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
import { saveWebsocketTriggerFromCfg } from './utils'
import { getHandlerType, handleConfigChange, type Trigger } from '../utils'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
@@ -105,6 +106,9 @@
let showLoading = $state(false)
let initialConfig: Record<string, any> | undefined = undefined
let deploymentLoading = $state(false)
let permissionedAs = $state<string | undefined>(undefined)
let selectedPermissionedAs = $state<string | undefined>(undefined)
let preservePermissionedAs = $state(false)
let isValid = $state(false)
let optionTabSelected: 'error_handler' | 'retries' = $state('error_handler')
let errorHandlerSelected: ErrorHandler = $state('slack')
@@ -234,6 +238,9 @@
retry = cfg?.retry
errorHandlerSelected = getHandlerType(error_handler_path ?? '')
mode = cfg?.mode ?? 'enabled'
permissionedAs = cfg?.permissioned_as
selectedPermissionedAs = undefined
preservePermissionedAs = false
}
function getSaveCfg() {
@@ -250,7 +257,9 @@
error_handler_path,
error_handler_args,
retry,
mode
mode,
permissioned_as: selectedPermissionedAs,
preserve_permissioned_as: preservePermissionedAs || undefined
}
}
@@ -438,6 +447,15 @@
<Loader2 class="animate-spin" />
{/if}
{:else}
{#if edit}
<PermissionedAsLine
{permissionedAs}
onPermissionedAsChange={(pa, preserve) => {
selectedPermissionedAs = pa
preservePermissionedAs = preserve
}}
/>
{/if}
<div class="flex flex-col gap-4">
{#if mode === 'suspended'}
<TriggerSuspendedJobsAlert {suspendedJobsModal} />
@@ -688,9 +706,11 @@
<Section label="Advanced" collapsable>
{#snippet header()}
<TriggerAdvancedBadges {error_handler_path} {retry} extraBadges={[
{ name: 'Filters', active: filters.length > 0 }
]} />
<TriggerAdvancedBadges
{error_handler_path}
{retry}
extraBadges={[{ name: 'Filters', active: filters.length > 0 }]}
/>
{/snippet}
<div class="flex flex-col gap-6">
<TriggerFilters bind:filters disabled={!can_write} />
@@ -29,7 +29,9 @@ export async function saveWebsocketTriggerFromCfg(
url_runnable_args: triggerCfg.url_runnable_args,
can_return_message: triggerCfg.can_return_message,
can_return_error_result: triggerCfg.can_return_error_result,
...errorHandlerAndRetries
...errorHandlerAndRetries,
permissioned_as: triggerCfg.permissioned_as,
preserve_permissioned_as: triggerCfg.preserve_permissioned_as
}
try {
if (edit) {
@@ -143,7 +143,7 @@
}
}
const emailPattern = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/
let emailValid = $derived(emailPattern.test(newEmail))
let passwordValid = $derived(newPassword.length >= 2)
let accountFormValid = $derived(emailValid && passwordValid)
+1 -1
View File
@@ -4,7 +4,7 @@ verify_ssl = true
name = "pypi"
[packages]
wmill = ">=1.662.0"
wmill = ">=1.663.0"
sendgrid = "*"
mysql-connector-python = "*"
pymongo = "*"
+1 -1
View File
@@ -1,7 +1,7 @@
openapi: '3.0.3'
info:
version: 1.662.0
version: 1.663.0
title: OpenFlow Spec
contact:
name: Ruben Fiszel
@@ -12,7 +12,7 @@
RootModule = 'WindmillClient.psm1'
# Version number of this module.
ModuleVersion = '1.662.0'
ModuleVersion = '1.663.0'
# Supported PSEditions
# CompatiblePSEditions = @()
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill"
version = "1.662.0"
version = "1.663.0"
description = "A client library for accessing Windmill server wrapping the Windmill client API"
license = "Apache-2.0"
homepage = "https://windmill.dev"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@windmill/windmill",
"version": "1.662.0",
"version": "1.663.0",
"exports": "./src/index.ts",
"publish": {
"exclude": ["!src", "./s3Types.ts", "./sqlUtils.ts", "./client.ts"]
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "windmill-client",
"description": "Windmill SDK client for browsers and Node.js",
"version": "1.662.0",
"version": "1.663.0",
"author": "Ruben Fiszel",
"license": "Apache 2.0",
"sideEffects": false,
+1 -1
View File
@@ -1 +1 @@
1.662.0
1.663.0