From 6e230a8ea26eb6344a1b1ca366794552b174ec10 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 24 Nov 2025 14:30:40 +0100 Subject: [PATCH 01/32] chore(main): release 1.583.2 (#7204) * chore(main): release 1.583.2 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> --- CHANGELOG.md | 8 + backend/Cargo.lock | 290 +++++++++--------- backend/Cargo.toml | 4 +- backend/windmill-api/openapi.yaml | 2 +- benchmarks/lib.ts | 2 +- cli/src/main.ts | 2 +- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- lsp/Pipfile | 4 +- openflow.openapi.yaml | 2 +- .../WindmillClient/WindmillClient.psd1 | 2 +- python-client/wmill/pyproject.toml | 2 +- python-client/wmill_pg/pyproject.toml | 2 +- typescript-client/jsr.json | 2 +- typescript-client/package.json | 2 +- version.txt | 2 +- 16 files changed, 169 insertions(+), 163 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 587414b789..ef9f014ee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.583.2](https://github.com/windmill-labs/windmill/compare/v1.583.1...v1.583.2) (2025-11-24) + + +### Bug Fixes + +* listScripts include description with opt-out query arg ([#7210](https://github.com/windmill-labs/windmill/issues/7210)) ([80c7911](https://github.com/windmill-labs/windmill/commit/80c79116416db8629135a8853df645d9fff286dd)) +* **scim:** use value instead of display for group updates ([#7203](https://github.com/windmill-labs/windmill/issues/7203)) ([193efe3](https://github.com/windmill-labs/windmill/commit/193efe31c8aeab3a5e3e28278855d518c000bda8)) + ## [1.583.1](https://github.com/windmill-labs/windmill/compare/v1.583.0...v1.583.1) (2025-11-21) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index ea9bffcffe..1828f8218b 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -556,7 +556,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -670,7 +670,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -692,7 +692,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -703,7 +703,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -800,9 +800,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5932a7d9d28b0d2ea34c6b3779d35e3dd6f6345317c34e73438c4f1f29144151" +checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f" dependencies = [ "aws-lc-sys", "zeroize", @@ -810,11 +810,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1826f2e4cfc2cd19ee53c42fbf68e2f81ec21108e0b7ecf6a71cf062137360fc" +checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6" dependencies = [ - "bindgen 0.72.1", "cc", "cmake", "dunce", @@ -896,9 +895,9 @@ dependencies = [ [[package]] name = "aws-sdk-rds" -version = "1.117.0" +version = "1.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b116d0229c41d5b72050dda07aa2cc7d1c571de8f7870c8b87fa297a724982" +checksum = "32ddd2f95d05c73d977308579961917c3b00bbacd36a592470111058a72582ac" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1298,7 +1297,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1438,7 +1437,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.110", + "syn 2.0.111", "which 4.4.2", ] @@ -1459,7 +1458,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1472,14 +1471,12 @@ dependencies = [ "cexpr", "clang-sys", "itertools 0.13.0", - "log", - "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1686,7 +1683,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1709,7 +1706,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1719,7 +1716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb" dependencies = [ "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1805,11 +1802,12 @@ dependencies = [ [[package]] name = "byte-unit" -version = "5.1.6" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" +checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" dependencies = [ "rust_decimal", + "schemars 1.1.0", "serde", "utf8-width", ] @@ -1853,7 +1851,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -1996,7 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5" dependencies = [ "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2148,7 +2146,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2203,7 +2201,7 @@ dependencies = [ "nom 7.1.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2585,7 +2583,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2678,7 +2676,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2692,7 +2690,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2725,7 +2723,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -2736,7 +2734,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -3228,7 +3226,7 @@ checksum = "df6f88d7ee27daf8b108ba910f9015176b36fbc72902b1ca5c2a5f1d1717e1a1" dependencies = [ "datafusion-expr", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -3666,7 +3664,7 @@ checksum = "babccedee31ce7e57c3e6dff2cb3ab8d68c49d0df8222fe0d11d628e65192790" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4057,7 +4055,7 @@ dependencies = [ "stringcase", "strum 0.25.0", "strum_macros 0.25.3", - "syn 2.0.110", + "syn 2.0.111", "thiserror 2.0.17", ] @@ -4559,7 +4557,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4580,7 +4578,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4624,7 +4622,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4644,7 +4642,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4770,7 +4768,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -4805,7 +4803,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5015,7 +5013,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5081,7 +5079,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5101,7 +5099,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5121,7 +5119,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5449,7 +5447,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5487,7 +5485,7 @@ checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" dependencies = [ "proc-macro2", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -5622,7 +5620,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -6007,7 +6005,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -6339,7 +6337,7 @@ checksum = "149e3ea90eb5a26ad354cfe3cb7f7401b9329032d0235f2687d03a35f30e5d4c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -7185,7 +7183,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -7536,7 +7534,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -7592,7 +7590,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8199,7 +8197,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8318,7 +8316,7 @@ checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8363,7 +8361,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "termcolor", "thiserror 2.0.17", ] @@ -8466,7 +8464,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8672,7 +8670,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -8940,7 +8938,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9168,7 +9166,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9632,7 +9630,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9713,7 +9711,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9763,7 +9761,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -9975,7 +9973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10039,7 +10037,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10050,7 +10048,7 @@ checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" dependencies = [ "proc-macro-rules-macros", "proc-macro2", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10062,7 +10060,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10173,7 +10171,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.110", + "syn 2.0.111", "tempfile", ] @@ -10187,7 +10185,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10597,7 +10595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" dependencies = [ "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10666,7 +10664,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -10981,7 +10979,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11071,7 +11069,7 @@ dependencies = [ "quote", "rust-embed-utils", "shellexpand", - "syn 2.0.110", + "syn 2.0.111", "walkdir", ] @@ -11559,7 +11557,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11571,7 +11569,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11760,7 +11758,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11771,7 +11769,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11823,7 +11821,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -11890,7 +11888,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12012,9 +12010,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -12321,7 +12319,7 @@ checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12386,7 +12384,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12409,7 +12407,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.110", + "syn 2.0.111", "tokio", "url", ] @@ -12573,7 +12571,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12642,7 +12640,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12654,7 +12652,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12773,7 +12771,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12822,7 +12820,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -12907,7 +12905,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13014,7 +13012,7 @@ checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13025,7 +13023,7 @@ checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13048,7 +13046,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13064,9 +13062,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.110" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -13108,7 +13106,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13466,7 +13464,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13477,7 +13475,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -13723,7 +13721,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -14153,7 +14151,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -14406,7 +14404,7 @@ checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -14721,9 +14719,9 @@ checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" [[package]] name = "utf8-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" [[package]] name = "utf8_iter" @@ -14889,7 +14887,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "wasm-bindgen-shared", ] @@ -14924,7 +14922,7 @@ checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -14959,7 +14957,7 @@ checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -15213,7 +15211,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "aws-sdk-config", @@ -15275,7 +15273,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "argon2", @@ -15396,7 +15394,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.583.1" +version = "1.583.2" dependencies = [ "base64 0.22.1", "chrono", @@ -15411,7 +15409,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.583.1" +version = "1.583.2" dependencies = [ "chrono", "lazy_static", @@ -15425,7 +15423,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "axum", @@ -15444,7 +15442,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "async-recursion", @@ -15533,7 +15531,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.583.1" +version = "1.583.2" dependencies = [ "regex", "serde", @@ -15548,7 +15546,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "bytes", @@ -15572,19 +15570,19 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.583.1" +version = "1.583.2" dependencies = [ "itertools 0.14.0", "lazy_static", "proc-macro2", "quote", "regex", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] name = "windmill-parser" -version = "1.583.1" +version = "1.583.2" dependencies = [ "convert_case 0.6.0", "serde", @@ -15593,7 +15591,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "lazy_static", @@ -15605,7 +15603,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "serde_json", @@ -15617,7 +15615,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "gosyn", @@ -15629,7 +15627,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "lazy_static", @@ -15641,7 +15639,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "serde_json", @@ -15653,7 +15651,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "nu-parser", @@ -15664,7 +15662,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15675,7 +15673,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15687,7 +15685,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "async-recursion", @@ -15710,7 +15708,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "lazy_static", @@ -15724,7 +15722,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15734,14 +15732,14 @@ dependencies = [ "quote", "regex", "serde_json", - "syn 2.0.110", + "syn 2.0.111", "toml", "windmill-parser", ] [[package]] name = "windmill-parser-sql" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "lazy_static", @@ -15755,7 +15753,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "lazy_static", @@ -15773,7 +15771,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "serde", @@ -15784,7 +15782,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "async-recursion", @@ -15821,7 +15819,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.583.1" +version = "1.583.2" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15831,7 +15829,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.583.1" +version = "1.583.2" dependencies = [ "anyhow", "async-once-cell", @@ -16047,7 +16045,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16058,7 +16056,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16069,7 +16067,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16080,7 +16078,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16091,7 +16089,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16102,7 +16100,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16610,7 +16608,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "synstructure 0.13.2", ] @@ -16622,7 +16620,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "synstructure 0.13.2", ] @@ -16643,7 +16641,7 @@ checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16663,7 +16661,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", "synstructure 0.13.2", ] @@ -16684,7 +16682,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] @@ -16717,7 +16715,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.111", ] [[package]] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 53dc39da96..9f103272dd 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.583.1" +version = "1.583.2" authors.workspace = true edition.workspace = true @@ -33,7 +33,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.583.1" +version = "1.583.2" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index b1e67ad122..51f1f59828 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.583.1 + version: 1.583.2 title: Windmill API contact: diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index 3b7305e758..c56563ab76 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -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.583.1"; +export const VERSION = "v1.583.2"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/src/main.ts b/cli/src/main.ts index fe41a1abed..9eb3c4a8b0 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.583.1"; +export const VERSION = "1.583.2"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 78b86f5a33..fa4b4ef279 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.583.1", + "version": "1.583.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.583.1", + "version": "1.583.2", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index a157a4954c..316627ea79 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.583.1", + "version": "1.583.2", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/lsp/Pipfile b/lsp/Pipfile index a9e0564f94..11db6eb91a 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.583.1" -wmill_pg = ">=1.583.1" +wmill = ">=1.583.2" +wmill_pg = ">=1.583.2" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 806265b17a..efde118054 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.583.1 + version: 1.583.2 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index 4e9fc0820f..12c6f20d6d 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.583.1' + ModuleVersion = '1.583.2' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 7c12ce1367..bcc29671b4 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.583.1" +version = "1.583.2" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index 1476130aee..b5bfd987bb 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.583.1" +version = "1.583.2" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 687dfeb075..954c93efc0 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.583.1", + "version": "1.583.2", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index 8c41eda35e..a6704bf45b 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.583.1", + "version": "1.583.2", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index d3ceef4475..68fa5724d3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.583.1 +1.583.2 From 29d8ad2e5de1447f39252edd5ceea22034801547 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 24 Nov 2025 15:03:40 +0000 Subject: [PATCH 02/32] fix(cli): fix pushing non existing apps with cli --- cli/src/commands/app/apps.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/src/commands/app/apps.ts b/cli/src/commands/app/apps.ts index 46dea1e349..1c6baceda2 100644 --- a/cli/src/commands/app/apps.ts +++ b/cli/src/commands/app/apps.ts @@ -45,7 +45,9 @@ export async function pushApp( } catch { //ignore } - app.policy = undefined; + if (app) { + app.policy = undefined; + } if (!localPath.endsWith(SEP)) { localPath += SEP; From 0e717c9588c1a3811cc4d438b53a93b4b13cf239 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 24 Nov 2025 17:15:10 +0000 Subject: [PATCH 03/32] fix: fix deadlock on oidc --- backend/ee-repo-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 7e7bbba899..ee9c8abbc4 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -17f318539d79d39d2dbba63a2b51d906f1732489 \ No newline at end of file +1de62d3f0901aac6ef9ddd7595e1032be56b1938 \ No newline at end of file From 1a1fdab5bd46eb98db25c72b3d0559a1e250aef8 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 24 Nov 2025 18:19:36 +0100 Subject: [PATCH 04/32] chore(main): release 1.583.3 (#7211) * chore(main): release 1.583.3 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> --- CHANGELOG.md | 8 + backend/Cargo.lock | 155 +++++++++--------- backend/Cargo.toml | 4 +- backend/windmill-api/openapi.yaml | 2 +- benchmarks/lib.ts | 2 +- cli/src/main.ts | 2 +- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- lsp/Pipfile | 4 +- openflow.openapi.yaml | 2 +- .../WindmillClient/WindmillClient.psd1 | 2 +- python-client/wmill/pyproject.toml | 2 +- python-client/wmill_pg/pyproject.toml | 2 +- typescript-client/jsr.json | 2 +- typescript-client/package.json | 2 +- version.txt | 2 +- 16 files changed, 102 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef9f014ee8..bb26b908fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.583.3](https://github.com/windmill-labs/windmill/compare/v1.583.2...v1.583.3) (2025-11-24) + + +### Bug Fixes + +* **cli:** fix pushing non existing apps with cli ([29d8ad2](https://github.com/windmill-labs/windmill/commit/29d8ad2e5de1447f39252edd5ceea22034801547)) +* fix deadlock on oidc ([0e717c9](https://github.com/windmill-labs/windmill/commit/0e717c9588c1a3811cc4d438b53a93b4b13cf239)) + ## [1.583.2](https://github.com/windmill-labs/windmill/compare/v1.583.1...v1.583.2) (2025-11-24) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 1828f8218b..eaabb783ab 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -645,7 +645,7 @@ checksum = "850b60ddcc664dcd848f8a2fa8436ab9336e051d6dd2b3f21f897dd8e9c24703" dependencies = [ "base64 0.22.1", "bytes", - "http 1.3.1", + "http 1.4.0", "rand 0.8.5", "reqwest 0.12.24", "serde", @@ -777,7 +777,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 1.3.1", + "http 1.4.0", "ring 0.17.14", "time", "tokio", @@ -1023,7 +1023,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "percent-encoding", "sha2 0.10.9", "time", @@ -1066,7 +1066,7 @@ dependencies = [ "futures-core", "futures-util", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "percent-encoding", "pin-project-lite", @@ -1086,7 +1086,7 @@ dependencies = [ "h2 0.3.27", "h2 0.4.12", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "hyper 0.14.32", "hyper 1.8.1", @@ -1147,7 +1147,7 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "pin-project-lite", @@ -1166,7 +1166,7 @@ dependencies = [ "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "pin-project-lite", "tokio", "tracing", @@ -1184,7 +1184,7 @@ dependencies = [ "bytes-utils", "futures-core", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -1243,7 +1243,7 @@ dependencies = [ "axum-macros", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -1277,7 +1277,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", @@ -1629,7 +1629,7 @@ dependencies = [ "futures-core", "futures-util", "hex", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-named-pipe", @@ -3478,7 +3478,7 @@ dependencies = [ "deno_error", "deno_media_type", "deno_path_util", - "http 1.3.1", + "http 1.4.0", "indexmap 2.11.1", "log", "once_cell", @@ -3686,7 +3686,7 @@ dependencies = [ "error_reporter", "h2 0.4.12", "hickory-resolver", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-rustls 0.27.7", @@ -3773,7 +3773,7 @@ dependencies = [ "deno_websocket", "flate2", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "httparse", "hyper 0.14.32", "hyper 1.8.1", @@ -3840,7 +3840,7 @@ dependencies = [ "denokv_remote", "denokv_sqlite", "faster-hex", - "http 1.3.1", + "http 1.4.0", "http-body-util", "log", "num-bigint", @@ -3967,7 +3967,7 @@ dependencies = [ "faster-hex", "h2 0.4.12", "hkdf", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-util", @@ -4237,7 +4237,7 @@ dependencies = [ "dlopen2 0.6.1", "encoding_rs", "fastwebsockets", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 0.14.32", "hyper 1.8.1", @@ -4422,7 +4422,7 @@ dependencies = [ "deno_tls", "fastwebsockets", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body-util", "hyper 1.8.1", "hyper-util", @@ -4485,7 +4485,7 @@ dependencies = [ "deno_error", "denokv_proto", "futures", - "http 1.3.1", + "http 1.4.0", "log", "prost", "rand 0.8.5", @@ -6100,7 +6100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de13e62d7e0ffc3eb40a0113ddf753cf6ec741be739164442b08893db4f9bfca" dependencies = [ "google-cloud-token", - "http 1.3.1", + "http 1.4.0", "thiserror 1.0.69", "tokio", "tokio-retry2", @@ -6260,7 +6260,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "indexmap 2.11.1", "slab", "tokio", @@ -6381,7 +6381,7 @@ dependencies = [ "base64 0.22.1", "bytes", "headers-core", - "http 1.3.1", + "http 1.4.0", "httpdate", "mime", "sha1", @@ -6393,7 +6393,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -6434,7 +6434,7 @@ checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97" dependencies = [ "dirs 6.0.0", "futures", - "http 1.3.1", + "http 1.4.0", "indicatif", "libc", "log", @@ -6580,12 +6580,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -6607,7 +6606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -6618,7 +6617,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -6676,7 +6675,7 @@ dependencies = [ "futures-channel", "futures-core", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", @@ -6697,7 +6696,7 @@ dependencies = [ "bytes", "futures-util", "headers", - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "hyper-rustls 0.27.7", "hyper-util", @@ -6745,7 +6744,7 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "hyper-util", "log", @@ -6811,7 +6810,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "hyper 1.8.1", "ipnet", @@ -7479,7 +7478,7 @@ dependencies = [ "either", "futures", "home", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -7513,7 +7512,7 @@ dependencies = [ "chrono", "derive_more 2.0.1", "form_urlencoded", - "http 1.3.1", + "http 1.4.0", "json-patch", "k8s-openapi", "schemars 0.8.22", @@ -8328,7 +8327,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.3.1", + "http 1.4.0", "httparse", "memchr", "mime", @@ -8956,7 +8955,7 @@ dependencies = [ "base64 0.22.1", "chrono", "getrandom 0.2.16", - "http 1.3.1", + "http 1.4.0", "rand 0.8.5", "reqwest 0.12.24", "serde", @@ -9005,7 +9004,7 @@ dependencies = [ "chrono", "form_urlencoded", "futures", - "http 1.3.1", + "http 1.4.0", "http-body-util", "httparse", "humantime", @@ -9123,7 +9122,7 @@ dependencies = [ "dyn-clone", "ed25519-dalek", "hmac", - "http 1.3.1", + "http 1.4.0", "itertools 0.10.5", "log", "oauth2", @@ -9231,7 +9230,7 @@ checksum = "10a8a7f5f6ba7c1b286c2fbca0454eaba116f63bbe69ed250b642d36fbb04d80" dependencies = [ "async-trait", "bytes", - "http 1.3.1", + "http 1.4.0", "opentelemetry", ] @@ -9243,7 +9242,7 @@ checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" dependencies = [ "async-trait", "futures-core", - "http 1.3.1", + "http 1.4.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", @@ -10772,7 +10771,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -10817,7 +10816,7 @@ checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" dependencies = [ "anyhow", "async-trait", - "http 1.3.1", + "http 1.4.0", "reqwest 0.12.24", "serde", "thiserror 1.0.69", @@ -10834,7 +10833,7 @@ dependencies = [ "async-trait", "futures", "getrandom 0.2.16", - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "parking_lot 0.11.2", "reqwest 0.12.24", @@ -10948,7 +10947,7 @@ dependencies = [ "bytes", "chrono", "futures", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "paste", @@ -13917,7 +13916,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "httparse", "rand 0.8.5", "ring 0.17.14", @@ -14005,7 +14004,7 @@ dependencies = [ "bytes", "flate2", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -14074,7 +14073,7 @@ dependencies = [ "axum-core", "cookie 0.18.1", "futures-util", - "http 1.3.1", + "http 1.4.0", "parking_lot 0.12.5", "pin-project-lite", "tower-layer", @@ -14093,7 +14092,7 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "iri-string", @@ -14338,7 +14337,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.3.1", + "http 1.4.0", "httparse", "log", "native-tls", @@ -15211,7 +15210,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "aws-sdk-config", @@ -15273,7 +15272,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "argon2", @@ -15315,7 +15314,7 @@ dependencies = [ "hex", "hf-hub", "hmac", - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "indexmap 2.11.1", "itertools 0.14.0", @@ -15394,7 +15393,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.583.2" +version = "1.583.3" dependencies = [ "base64 0.22.1", "chrono", @@ -15409,7 +15408,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.583.2" +version = "1.583.3" dependencies = [ "chrono", "lazy_static", @@ -15423,7 +15422,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "axum", @@ -15442,7 +15441,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "async-recursion", @@ -15531,7 +15530,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.583.2" +version = "1.583.3" dependencies = [ "regex", "serde", @@ -15546,7 +15545,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "bytes", @@ -15570,7 +15569,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.583.2" +version = "1.583.3" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -15582,7 +15581,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.583.2" +version = "1.583.3" dependencies = [ "convert_case 0.6.0", "serde", @@ -15591,7 +15590,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "lazy_static", @@ -15603,7 +15602,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "serde_json", @@ -15615,7 +15614,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "gosyn", @@ -15627,7 +15626,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "lazy_static", @@ -15639,7 +15638,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "serde_json", @@ -15651,7 +15650,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "nu-parser", @@ -15662,7 +15661,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15673,7 +15672,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15685,7 +15684,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "async-recursion", @@ -15708,7 +15707,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "lazy_static", @@ -15722,7 +15721,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15739,7 +15738,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "lazy_static", @@ -15753,7 +15752,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "lazy_static", @@ -15771,7 +15770,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "serde", @@ -15782,7 +15781,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "async-recursion", @@ -15819,7 +15818,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.583.2" +version = "1.583.3" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15829,7 +15828,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.583.2" +version = "1.583.3" dependencies = [ "anyhow", "async-once-cell", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 9f103272dd..30d36d0c09 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.583.2" +version = "1.583.3" authors.workspace = true edition.workspace = true @@ -33,7 +33,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.583.2" +version = "1.583.3" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 51f1f59828..48b2a2a08a 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.583.2 + version: 1.583.3 title: Windmill API contact: diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index c56563ab76..3a9f64ee6b 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -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.583.2"; +export const VERSION = "v1.583.3"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/src/main.ts b/cli/src/main.ts index 9eb3c4a8b0..f45ca3607e 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.583.2"; +export const VERSION = "1.583.3"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fa4b4ef279..8dc67ac1c6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.583.2", + "version": "1.583.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.583.2", + "version": "1.583.3", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 316627ea79..202b2f17c3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.583.2", + "version": "1.583.3", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/lsp/Pipfile b/lsp/Pipfile index 11db6eb91a..ef9fbe6a18 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.583.2" -wmill_pg = ">=1.583.2" +wmill = ">=1.583.3" +wmill_pg = ">=1.583.3" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index efde118054..5145d2884f 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.583.2 + version: 1.583.3 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index 12c6f20d6d..9d17deaa98 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.583.2' + ModuleVersion = '1.583.3' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index bcc29671b4..10af1ba2c2 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.583.2" +version = "1.583.3" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index b5bfd987bb..f7824560f2 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.583.2" +version = "1.583.3" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 954c93efc0..30478fca0b 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.583.2", + "version": "1.583.3", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index a6704bf45b..b734e93d31 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.583.2", + "version": "1.583.3", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index 68fa5724d3..f511ac6fe7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.583.2 +1.583.3 From 2bd2bfec9ab7d2534472dc664527f27c617fecd3 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:39:19 +0100 Subject: [PATCH 05/32] fix update sqlx git command (#7212) --- .github/workflows/git-commands.yaml | 18 +++++++++++++----- backend/update_sqlx.sh | 9 --------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/git-commands.yaml b/.github/workflows/git-commands.yaml index 7c7a05e81e..7e8a5e2acf 100644 --- a/.github/workflows/git-commands.yaml +++ b/.github/workflows/git-commands.yaml @@ -82,6 +82,10 @@ jobs: run: | set -e # Exit on any command failure PR_NUMBER=${{ github.event.issue.number }} + + # Set up error trap to comment on PR for any failure + trap 'gh pr comment $PR_NUMBER --body "❌ SQLx update failed. Please check the workflow logs for details."' ERR + BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName) echo "Checking out PR branch: $BRANCH_NAME" git checkout $BRANCH_NAME @@ -93,10 +97,8 @@ jobs: cd backend cargo install sqlx-cli --version 0.8.5 sqlx migrate run - if ! ./update_sqlx.sh --dir ./windmill-ee-private; then - gh pr comment $PR_NUMBER --body "❌ SQLx update failed. Please check the workflow logs for details." - exit 1 - fi + ./substitute_ee_code.sh --dir ./windmill-ee-private + ./update_sqlx.sh # Pass the branch name to the next step echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV @@ -216,11 +218,12 @@ jobs: with: github-token: ${{ steps.app.outputs.token }} script: | + const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: 'Starting ee ref update...' + body: `Starting ee ref update...\n\n[View workflow run](${runUrl})` }) - name: Checkout repository @@ -249,7 +252,12 @@ jobs: env: GH_TOKEN: ${{ steps.app.outputs.token }} run: | + set -e # Exit on any command failure PR_NUMBER=${{ github.event.issue.number }} + + # Set up error trap to comment on PR for any failure + trap 'gh pr comment $PR_NUMBER --body "❌ EE ref update failed. Please check the workflow logs for details."' ERR + BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName) echo "Checking out PR branch: $BRANCH_NAME" git checkout $BRANCH_NAME diff --git a/backend/update_sqlx.sh b/backend/update_sqlx.sh index 5425706876..669aa90dc9 100755 --- a/backend/update_sqlx.sh +++ b/backend/update_sqlx.sh @@ -2,15 +2,6 @@ set -e -# Parse arguments -while [[ "$#" -gt 0 ]]; do - case $1 in - --dir) EE_DIR="$2"; shift ;; - *) echo "Unknown parameter: $1"; exit 1 ;; - esac - shift -done - # Check if running on macOS if [[ "$(uname)" == "Darwin" ]]; then echo "Running on macOS - substituting samael..." From c47669be0bffb0821afe9d4182cc071cb3b675f0 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Mon, 24 Nov 2025 18:39:35 +0100 Subject: [PATCH 06/32] feat(app): add chat component (#7199) * draft * fix * use user message * correctly stream * add send trigger * add control * fix on success trigger * add warning about expected input * nit * styling * fix stream * styling * dry * dry * nit * better logic * css * cleaning * use managed by component input * fix * fix managed inputs * handle memory * cleaning * cleaning * cleaning * update sqlx * use id --- ...1f7f387f5055c47f493271d26731336257384.json | 10 +- ...7f49c589465194548d88e5ae30872846b70a9.json | 22 ++ ...a90d9206c45d92a0423c0bc2396d0d66a0b0d.json | 4 +- ...51312794c22d6337be897bc618585fa5b27f3.json | 15 + ...f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json | 15 - backend/windmill-api/openapi.yaml | 3 + backend/windmill-api/src/apps.rs | 19 +- .../windmill-api/src/flow_conversations.rs | 2 + backend/windmill-api/src/jobs.rs | 19 +- .../windmill-common/src/flow_conversations.rs | 19 + .../apps/components/componentManagedFields.ts | 97 +++++ .../apps/components/display/AppChat.svelte | 338 ++++++++++++++++++ .../helpers/RunnableComponent.svelte | 33 +- .../components/helpers/RunnableWrapper.svelte | 1 + .../apps/components/helpers/eval.ts | 7 +- .../components/helpers/executeRunnable.ts | 7 +- .../editor/component/ComponentInner.svelte | 12 + .../apps/editor/component/components.ts | 72 +++- .../apps/editor/component/default-codes.ts | 13 + .../components/apps/editor/component/sets.ts | 1 + .../componentsPanel/componentControlUtils.ts | 8 + .../apps/editor/componentsPanel/cssUtils.ts | 27 +- .../componentsPanel/quickStyleProperties.ts | 8 + .../InlineScriptEditor.svelte | 54 +-- .../settingsPanel/ComponentPanel.svelte | 24 +- .../inputEditor/RunnableInputEditor.svelte | 10 +- .../apps/editor/settingsPanel/script/utils.ts | 9 +- frontend/src/lib/components/apps/types.ts | 1 + frontend/src/lib/components/apps/utils.ts | 6 + .../src/lib/components/chat/ChatInput.svelte | 87 +++++ .../lib/components/chat/ChatMessage.svelte | 127 +++++++ frontend/src/lib/components/chat/utils.ts | 30 ++ .../conversations/FlowChatInterface.svelte | 62 ++-- .../conversations/FlowChatManager.svelte.ts | 34 +- .../conversations/FlowChatMessage.svelte | 93 ----- 35 files changed, 1026 insertions(+), 263 deletions(-) create mode 100644 backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json create mode 100644 backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json delete mode 100644 backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json create mode 100644 frontend/src/lib/components/apps/components/componentManagedFields.ts create mode 100644 frontend/src/lib/components/apps/components/display/AppChat.svelte create mode 100644 frontend/src/lib/components/chat/ChatInput.svelte create mode 100644 frontend/src/lib/components/chat/ChatMessage.svelte create mode 100644 frontend/src/lib/components/chat/utils.ts delete mode 100644 frontend/src/lib/components/flows/conversations/FlowChatMessage.svelte diff --git a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json index d29a18c691..e7ed0aee65 100644 --- a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json +++ b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json @@ -46,11 +46,11 @@ ] }, "nullable": [ - true, - true, - true, - true, - true, + false, + false, + false, + false, + false, true, true ] diff --git a/backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json b/backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json new file mode 100644 index 0000000000..2348defd19 --- /dev/null +++ b/backend/.sqlx/query-086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1) as \"exists!\"", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + null + ] + }, + "hash": "086fdf726b88e9f4fd9750bf9dd7f49c589465194548d88e5ae30872846b70a9" +} diff --git a/backend/.sqlx/query-0a7132202ecf6c4c10340921644a90d9206c45d92a0423c0bc2396d0d66a0b0d.json b/backend/.sqlx/query-0a7132202ecf6c4c10340921644a90d9206c45d92a0423c0bc2396d0d66a0b0d.json index bc15928e38..ecaf828737 100644 --- a/backend/.sqlx/query-0a7132202ecf6c4c10340921644a90d9206c45d92a0423c0bc2396d0d66a0b0d.json +++ b/backend/.sqlx/query-0a7132202ecf6c4c10340921644a90d9206c45d92a0423c0bc2396d0d66a0b0d.json @@ -59,9 +59,7 @@ "failure", "command", "approval", - "preprocessor", - "schedule_handler_old", - "dynamic_skip" + "preprocessor" ] } } diff --git a/backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json b/backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json new file mode 100644 index 0000000000..46d591b6a1 --- /dev/null +++ b/backend/.sqlx/query-348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE v2_job_status\n SET flow_status = jsonb_set(\n flow_status,\n '{memory_id}',\n to_jsonb($2::uuid)\n )\n WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "348d64dc9f81f04538c5fec98df51312794c22d6337be897bc618585fa5b27f3" +} diff --git a/backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json b/backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json deleted file mode 100644 index 68461c0c98..0000000000 --- a/backend/.sqlx/query-f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "UPDATE v2_job_status \n SET flow_status = jsonb_set(\n flow_status,\n '{memory_id}',\n to_jsonb($2::uuid)\n )\n WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Uuid" - ] - }, - "nullable": [] - }, - "hash": "f5568a691ec5931634cf986f806f5eae7bb8ed0f5c6e54ca3f49a991c53ed50d" -} diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 48b2a2a08a..49d85ec411 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -7707,6 +7707,9 @@ paths: type: array items: type: string + run_query_params: + type: object + description: Runnable query parameters required: - args - component diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index c7b1bd18bc..4849824b0a 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -10,6 +10,7 @@ use std::{collections::HashMap, sync::Arc}; use crate::{ auth::OptTokened, db::{ApiAuthed, DB}, + jobs::RunJobQuery, resources::get_resource_value_interpolated_internal, users::{require_owner_of_path, OptAuthed}, utils::{check_scopes, WithStarredInfoQuery}, @@ -1654,6 +1655,8 @@ pub struct ExecuteApp { pub force_viewer_static_fields: Option, pub force_viewer_one_of_fields: Option, pub force_viewer_allow_user_resources: Option, + /// Runnable query parameters (e.g., memory_id for chat-enabled flows) + pub run_query_params: Option, } fn digest(code: &str) -> String { @@ -1894,6 +1897,12 @@ async fn execute_component( ) .await?; + let is_flow = payload + .path + .as_ref() + .map(|p| p.starts_with("flow/")) + .unwrap_or(false); + let (job_payload, tag, on_behalf_of) = match (payload.path, payload.raw_code, payload.id) { // flow or script: (Some(path), None, None) => get_payload_tag_from_prefixed_path(&path, &db, &w_id).await?, @@ -1920,7 +1929,7 @@ async fn execute_component( let end_user_email = opt_authed.as_ref().map(|a| a.email.clone()); - let (uuid, tx) = push( + let (uuid, mut tx) = push( &db, tx, &w_id, @@ -1954,6 +1963,14 @@ async fn execute_component( None, ) .await?; + + // Apply runnable query parameters if provided + if let Some(ref run_query) = payload.run_query_params { + if is_flow { + crate::jobs::process_flow_run_query_params(&mut tx, uuid, run_query).await?; + } + } + tx.commit().await?; Ok(uuid.to_string()) diff --git a/backend/windmill-api/src/flow_conversations.rs b/backend/windmill-api/src/flow_conversations.rs index 0cbdb7aa55..4854615c18 100644 --- a/backend/windmill-api/src/flow_conversations.rs +++ b/backend/windmill-api/src/flow_conversations.rs @@ -134,6 +134,7 @@ pub async fn get_or_create_conversation_with_id( } else { title.to_string() }; + // Create new conversation with provided ID let conversation = sqlx::query_as!( FlowConversation, @@ -148,6 +149,7 @@ pub async fn get_or_create_conversation_with_id( ) .fetch_one(&mut **tx) .await?; + Ok(conversation) } diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index dcb2b6cd08..86e16a3bb0 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -1740,7 +1740,7 @@ pub struct ListableCompletedJob { pub labels: Option, } -#[derive(Deserialize, Clone, Default)] +#[derive(Debug, Deserialize, Clone, Default)] pub struct RunJobQuery { pub scheduled_for: Option>, pub scheduled_in_secs: Option, @@ -3947,7 +3947,7 @@ async fn set_flow_memory_id( memory_id: Uuid, ) -> error::Result<()> { sqlx::query!( - "UPDATE v2_job_status + "UPDATE v2_job_status SET flow_status = jsonb_set( flow_status, '{memory_id}', @@ -3962,6 +3962,19 @@ async fn set_flow_memory_id( Ok(()) } +/// Apply flow-specific query parameters after job creation +pub async fn process_flow_run_query_params( + tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, + job_id: Uuid, + run_query: &RunJobQuery, +) -> error::Result<()> { + // Set memory_id if provided (for agent memory) + if let Some(memory_id) = run_query.memory_id { + set_flow_memory_id(tx, job_id, memory_id).await?; + } + Ok(()) +} + async fn handle_chat_conversation_messages( tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, authed: &ApiAuthed, @@ -5670,7 +5683,7 @@ pub async fn stream_job( version, run_query, args, - None + None, ) .await? .0 diff --git a/backend/windmill-common/src/flow_conversations.rs b/backend/windmill-common/src/flow_conversations.rs index 8826f85b94..472c9c264c 100644 --- a/backend/windmill-common/src/flow_conversations.rs +++ b/backend/windmill-common/src/flow_conversations.rs @@ -15,6 +15,8 @@ pub enum MessageType { } /// Add a message to a conversation using an existing transaction +/// If the conversation doesn't exist, logs a warning and returns Ok (no error thrown) +/// This allows memory_id to be used for agent memory without requiring a conversation pub async fn add_message_to_conversation_tx( tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, conversation_id: Uuid, @@ -24,6 +26,23 @@ pub async fn add_message_to_conversation_tx( step_name: Option<&str>, success: bool, ) -> Result<()> { + // Check if conversation exists first + let conversation_exists = sqlx::query!( + "SELECT EXISTS(SELECT 1 FROM flow_conversation WHERE id = $1) as \"exists!\"", + conversation_id + ) + .fetch_one(&mut **tx) + .await? + .exists; + + if !conversation_exists { + tracing::warn!( + "Conversation {} does not exist. Skipping message insertion. This is expected when flows are called from apps (memory_id is used for agent memory only).", + conversation_id + ); + return Ok(()); + } + // Insert the message sqlx::query!( "INSERT INTO flow_conversation_message (conversation_id, message_type, content, job_id, step_name, success) diff --git a/frontend/src/lib/components/apps/components/componentManagedFields.ts b/frontend/src/lib/components/apps/components/componentManagedFields.ts new file mode 100644 index 0000000000..0a9f39854d --- /dev/null +++ b/frontend/src/lib/components/apps/components/componentManagedFields.ts @@ -0,0 +1,97 @@ +/** + * Component-Managed Fields Registry + * + * This module provides a centralized registry of fields that are automatically + * managed by components at runtime, rather than being configured by users. + * + * These fields should never be treated as static fields in force_viewer_static_fields, + * as their values are determined dynamically by user interactions (pagination, + * sorting, search, chat input, etc.) + */ + +import type { AppInput } from '$lib/components/apps/inputType' + +/** + * Registry of component types to their managed field names + */ +export const COMPONENT_MANAGED_FIELDS: Record = { + aggridinfinitecomponent: ['offset', 'limit', 'orderBy', 'isDesc', 'search'], + aggridinfinitecomponentee: ['offset', 'limit', 'orderBy', 'isDesc', 'search'], + chatcomponent: ['user_message'] +} + +/** + * Get the list of managed fields for a given component type + */ +export function getManagedFields(componentType: string): string[] { + return COMPONENT_MANAGED_FIELDS[componentType] ?? [] +} + +/** + * Check if a field is managed by a specific component type + */ +export function isFieldManagedByComponent(componentType: string, fieldName: string): boolean { + const managedFields = getManagedFields(componentType) + return managedFields.includes(fieldName) +} + +/** + * Convert component-managed fields from static to evalv2 type + * This ensures they are properly handled at runtime and not added to force_viewer_static_fields + */ +export function convertManagedFieldsToEvalv2( + componentType: string, + componentId: string, + fields: Record +): Record { + const managedFieldNames = getManagedFields(componentType) + + if (managedFieldNames.length === 0) { + return fields + } + + const convertedFields = { ...fields } + + for (const fieldName of managedFieldNames) { + if (convertedFields[fieldName]) { + // Determine the expression based on component type + let expr: string + + if ( + componentType === 'aggridinfinitecomponent' || + componentType === 'aggridinfinitecomponentee' + ) { + // AgGrid components use params.{fieldName} + expr = `${componentId}.params.${fieldName}` + } else if (componentType === 'chatcomponent') { + // Chat component uses userMessage output + expr = `${componentId}.userMessage` + } else { + // Default pattern for future components + expr = `${componentId}.${fieldName}` + } + + // Convert to evalv2 type while preserving fieldType + convertedFields[fieldName] = { + type: 'evalv2', + expr, + fieldType: convertedFields[fieldName].fieldType ?? 'string', + connections: [] + } as AppInput + } + } + + return convertedFields +} + +/** + * Get all managed field names across all component types + * Useful for generic checks + */ +export function getAllManagedFieldNames(): string[] { + const allFields = new Set() + Object.values(COMPONENT_MANAGED_FIELDS).forEach((fields) => { + fields.forEach((field) => allFields.add(field)) + }) + return Array.from(allFields) +} diff --git a/frontend/src/lib/components/apps/components/display/AppChat.svelte b/frontend/src/lib/components/apps/components/display/AppChat.svelte new file mode 100644 index 0000000000..49e6f5d2a1 --- /dev/null +++ b/frontend/src/lib/components/apps/components/display/AppChat.svelte @@ -0,0 +1,338 @@ + + + + +{#each Object.keys(components['chatcomponent'].initialData.configuration) as key (key)} + +{/each} + +{#each Object.keys(css ?? {}) as key (key)} + +{/each} + + + {#if render} +
+ +
+ {#if messages.length === 0} +
+ No messages yet. Start a conversation! +
+ {:else} +
+ {#each messages as message (message.id)} + + {/each} + {#if loading} +
+ + Processing... +
+ {/if} +
+ {/if} +
+ + +
+ +
+
+ {/if} +
diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte index d66675bbe8..0cba5da33e 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte @@ -197,6 +197,7 @@ result_stream?: string }) { setResult(nresult_stream, id, false) + dispatch('streamupdate', { id, result_stream: nresult_stream }) }, cancel({ id }: { id: string }) { onCancel?.() @@ -442,7 +443,8 @@ $appPath, id, await buildRequestBody(dynamicArgsOverride), - inlineScriptOverride + inlineScriptOverride, + extraQueryParams ) if (isEditor) { addJob(uuid) @@ -473,35 +475,36 @@ } export async function buildRequestBody(dynamicArgsOverride: Record | undefined) { - const nonStaticRunnableInputs = dynamicArgsOverride ?? {} - const staticRunnableInputs = {} + const nonStaticRunnableInputs: Record = dynamicArgsOverride ?? {} + const staticRunnableInputs: Record = {} const allowUserResources: string[] = [] + for (const k of Object.keys(fields ?? {})) { - let field = fields[k] - if (field?.type == 'static' && fields[k]) { + const field = fields[k] + + if ( + isEditor && + ['user', 'evalv2', 'connected'].includes(field.type) && + 'allowUserResources' in field && + field.allowUserResources + ) { + allowUserResources.push(k) + } + + if (field?.type == 'static') { if (isEditor) { staticRunnableInputs[k] = field.value } } else if (field?.type == 'user') { nonStaticRunnableInputs[k] = args?.[k] - if (isEditor && field.allowUserResources) { - allowUserResources.push(k) - } } else if (field?.type == 'eval' || (field?.type == 'evalv2' && inputValues[k])) { const ctxMatch = field?.expr?.match(ctxRegex) if (ctxMatch) { nonStaticRunnableInputs[k] = '$ctx:' + ctxMatch[1] } else { - // console.log('k', k) nonStaticRunnableInputs[k] = await inputValues[k]?.computeExpr() } - if (isEditor && field?.type == 'evalv2' && field.allowUserResources) { - allowUserResources.push(k) - } } else { - if (isEditor && field?.type == 'connected' && field.allowUserResources) { - allowUserResources.push(k) - } nonStaticRunnableInputs[k] = runnableInputValues[k] } } diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte index 9751363445..9553655799 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableWrapper.svelte @@ -360,6 +360,7 @@ on:cancel on:recompute on:argsChanged + on:streamupdate on:resultSet={(e) => { const res = e.detail if ($initialized?.runnableInitialized?.[fullId] === undefined) { diff --git a/frontend/src/lib/components/apps/components/helpers/eval.ts b/frontend/src/lib/components/apps/components/helpers/eval.ts index bb737040bd..d8cf4ea1ea 100644 --- a/frontend/src/lib/components/apps/components/helpers/eval.ts +++ b/frontend/src/lib/components/apps/components/helpers/eval.ts @@ -31,7 +31,7 @@ function create_context_function_template( ) { let hasReturnAsLastLine = noReturn || eval_string.split('\n').some((x) => x.startsWith('return ')) return ` -return async function (context, state, createProxy, goto, setTab, recompute, globalRecompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, showToast, waitJob, askNewResource, downloadFile) { +return async function (context, state, createProxy, goto, setTab, recompute, globalRecompute, getAgGrid, setValue, setSelectedIndex, openModal, closeModal, open, close, validate, invalidate, validateAll, clearFiles, sendMessage, showToast, waitJob, askNewResource, downloadFile) { "use strict"; ${ contextKeys && contextKeys.length > 0 @@ -68,6 +68,7 @@ type WmFunctor = ( invalidate, validateAll, clearFiles, + sendMessage, showToast, waitJob, askNewResource, @@ -123,6 +124,7 @@ export async function eval_like( waitJob?: (jobId: string) => void askNewResource?: () => void setGroupValue?: (key: string, value: any) => void + sendMessage?: (message: string) => void } >, worldStore: World | undefined, @@ -246,6 +248,9 @@ export async function eval_like( (id) => { controlComponents[id]?.clearFiles?.() }, + (id, message) => { + controlComponents[id]?.sendMessage?.(message) + }, (message, error) => { sendUserToast(message, error) }, diff --git a/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts b/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts index 397f690ae2..367ec0795f 100644 --- a/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts +++ b/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts @@ -11,7 +11,8 @@ export async function executeRunnable( path: string, id: string, requestBody: ExecuteComponentData['requestBody'], - inlineScriptOverride?: InlineScript + inlineScriptOverride?: InlineScript, + queryParams?: Record ) { let appPath = defaultIfEmptyString(path, `u/${username ?? 'unknown'}/newapp`) if (runnable?.type === 'runnableByName') { @@ -40,6 +41,10 @@ export async function executeRunnable( requestBody['version'] = version } + if (queryParams && Object.keys(queryParams).length > 0) { + requestBody['run_query_params'] = queryParams + } + const uuid = await AppService.executeComponent({ workspace, path: appPath, diff --git a/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte b/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte index 14b19bf719..40261e9260 100644 --- a/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte +++ b/frontend/src/lib/components/apps/editor/component/ComponentInner.svelte @@ -52,6 +52,7 @@ import AppDateInput from '../../components/inputs/AppDateInput.svelte' import AppSelect from '../../components/inputs/AppSelect.svelte' import AppBarChart from '../../components/display/AppBarChart.svelte' + import AppChat from '../../components/display/AppChat.svelte' import AppDivider from '../../components/layout/AppDivider.svelte' import AppRangeInput from '../../components/inputs/AppRangeInput.svelte' import AppTabs from '../../components/layout/AppTabs.svelte' @@ -110,6 +111,7 @@ 'carousellistcomponent', 'chartjscomponent', 'chartjscomponentv2', + 'chatcomponent', 'checkboxcomponent', 'codeinputcomponent', 'conditionalwrapper', @@ -340,6 +342,16 @@ xData={component.xData} {render} /> + {:else if component.type === 'chatcomponent'} + {:else if component.type === 'checkboxcomponent'} +export type ChatComponent = BaseComponent<'chatcomponent'> & RecomputeOthersSource export type JobIdDisplayComponent = BaseComponent<'jobiddisplaycomponent'> export type LogComponent = BaseComponent<'logcomponent'> export type JobIdLogComponent = BaseComponent<'jobidlogcomponent'> @@ -338,6 +340,7 @@ export type RecomputeAllComponent = BaseComponent<'recomputeallcomponent'> export type TypedComponent = | DBExplorerComponent | DisplayComponent + | ChatComponent | LogComponent | JobIdLogComponent | FlowStatusComponent @@ -461,6 +464,23 @@ export type AppComponentConfig = { */ initialData: InitialAppComponent customCss: ComponentCustomCSS + /** + * Optional configuration for runnable inputs validation + */ + runnableInputsInfo?: { + /** + * Function to validate runnable inputs and return a warning if needed + * @param fields - The fields object from componentInput.fields + * @returns Warning object with type, title, and message, or undefined if valid + */ + validate?: (fields: Record) => + | { + type: 'warning' | 'error' | 'info' + title: string + message: string + } + | undefined + } } export type PresetComponentConfig = { @@ -1128,6 +1148,56 @@ export const components = { } } }, + chatcomponent: { + name: 'Chat', + icon: MessageSquare, + documentationLink: `${documentationBaseUrl}/chat`, + dims: '3:8-6:12' as AppComponentDimensions, + customCss: { + container: { class: '', style: '' }, + messagesContainer: { class: '', style: '' }, + inputContainer: { class: '', style: '' }, + userMessage: { class: '', style: '' }, + assistantMessage: { class: '', style: '' }, + input: { class: '', style: '' }, + button: { class: '', style: '' } + }, + runnableInputsInfo: { + validate: (fields) => { + const fieldNames = Object.keys(fields) + const hasUserMessage = fieldNames.includes('user_message') + + if (!hasUserMessage) { + return { + type: 'warning' as const, + title: 'Chat input configuration', + message: + 'The chat component requires a user_message parameter to work. Please add it to your event handler.' + } + } + + return undefined + } + }, + initialData: { + componentInput: { + type: 'runnable', + fieldType: 'any', + fields: {}, + runnable: undefined + }, + recomputeIds: true, + configuration: { + placeholder: { + type: 'static', + fieldType: 'text', + value: 'Type a message...' + }, + onSuccess: onSuccessClick, + onError: onErrorClick + } + } + }, jobidlogcomponent: { name: 'Log by Job Id', icon: Monitor, diff --git a/frontend/src/lib/components/apps/editor/component/default-codes.ts b/frontend/src/lib/components/apps/editor/component/default-codes.ts index 51b3353724..6a00a47cd9 100644 --- a/frontend/src/lib/components/apps/editor/component/default-codes.ts +++ b/frontend/src/lib/components/apps/editor/component/default-codes.ts @@ -765,5 +765,18 @@ return { }`, python3: `def main(): return [{"foo": 1}, {"foo": 2}, {"foo": 3}]` + }, + chatcomponent: { + deno: `export async function main(user_message: string) { + // Process the user message here + // You can call APIs, query databases, use AI models, etc. + + return "Hi, how are you?"; +}`, + python3: `def main(user_message: str): + # Process the user message here + # You can call APIs, query databases, use AI models, etc. + + return "Hi, how are you?"` } } as const diff --git a/frontend/src/lib/components/apps/editor/component/sets.ts b/frontend/src/lib/components/apps/editor/component/sets.ts index c67beee550..53e551e51a 100644 --- a/frontend/src/lib/components/apps/editor/component/sets.ts +++ b/frontend/src/lib/components/apps/editor/component/sets.ts @@ -73,6 +73,7 @@ const display: ComponentSet = { 'htmlcomponent', 'mardowncomponent', 'pdfcomponent', + 'chatcomponent', 'displaycomponent', 'jobidlogcomponent', 'jobidflowstatuscomponent', diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts b/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts index a74198b562..ad7e0b7641 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts +++ b/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts @@ -83,6 +83,12 @@ const validateAll = { example: 'validateAll(id: string, key: string)' } +const sendMessage = { + title: 'sendMessage', + description: 'Programmatically send a message to the chat component', + example: 'sendMessage(id: string, message: string)' +} + export function getComponentControl(type: keyof typeof components): Array { switch (type) { case 'tabscomponent': @@ -135,6 +141,8 @@ export function getComponentControl(type: keyof typeof components): Array { - if (newFields[field]?.type !== 'evalv2') { - newFields[field] = { - type: 'evalv2', - expr: `${id}.params.${field}`, - fieldType: newFields[field]?.fieldType ?? 'string' - } - } - }) - } + // Convert component-managed fields to evalv2 type using centralized utility + // This ensures that even if fields were somehow changed, they remain as evalv2 + const convertedFields = convertManagedFieldsToEvalv2(componentType ?? '', id, newFields) + Object.assign(newFields, convertedFields) } async function loadSchemaAndInputsByName() { diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte index fd18def723..e93c507e41 100644 --- a/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte +++ b/frontend/src/lib/components/apps/editor/settingsPanel/ComponentPanel.svelte @@ -1,5 +1,6 @@ + +
+ + {#if showCancelButton && onCancel} +
diff --git a/frontend/src/lib/components/chat/ChatMessage.svelte b/frontend/src/lib/components/chat/ChatMessage.svelte new file mode 100644 index 0000000000..f811abd0a2 --- /dev/null +++ b/frontend/src/lib/components/chat/ChatMessage.svelte @@ -0,0 +1,127 @@ + + +
+ {#if stepName} +
+ {stepName} +
+ {/if} + + {#if role === 'user'} +

{content}

+ {:else if loading} +
+ + Processing... +
+ {:else if content} + {#if s3Object} +
+ +
+ {:else if enableMarkdown} +
+ {#if role === 'tool'} + {#if success !== false} + + {:else} + + {/if} + {/if} +
+ +
+
+ {:else} +

{content}

+ {/if} + {:else} +

No result

+ {/if} +
diff --git a/frontend/src/lib/components/chat/utils.ts b/frontend/src/lib/components/chat/utils.ts new file mode 100644 index 0000000000..60f59fce10 --- /dev/null +++ b/frontend/src/lib/components/chat/utils.ts @@ -0,0 +1,30 @@ +export function parseStreamDeltas(streamData: string): { + content: string + type?: string + success?: boolean +} { + const lines = streamData.trim().split('\n') + let content = '' + let type = 'message' + let success = true + + for (const line of lines) { + if (!line.trim()) continue + try { + const parsed = JSON.parse(line) + if (parsed.type === 'tool_result') { + type = 'tool_result' + success = parsed.success + const toolName = parsed.function_name + content = success ? `Used ${toolName} tool` : `Failed to use ${toolName} tool` + } + if (parsed.type === 'token_delta' && parsed.content) { + content += parsed.content + } + } catch (e) { + console.error('Failed to parse stream line:', line, e) + } + } + + return { content, type, success } +} diff --git a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte index 7bbad19d25..99e3c84f88 100644 --- a/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte +++ b/frontend/src/lib/components/flows/conversations/FlowChatInterface.svelte @@ -1,8 +1,8 @@ - -
- {#if message.step_name} -
{message.step_name}
- {/if} - - {#if message.message_type === 'user'} -

{message.content}

- {:else if message.loading} -
- - Processing... -
- {:else if message.content} - {#if s3Object} -
- -
- {:else} -
- {#if message.message_type === 'tool'} - {#if message.success !== false} - - {:else} - - {/if} - {/if} -
- -
-
- {/if} - {:else} -

No result

- {/if} -
From 7eed0ddd8ef0f75a189e7238718906ae5a05ffd3 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 24 Nov 2025 20:37:08 +0100 Subject: [PATCH 07/32] remove outdated tooltip (#7216) --- .../src/lib/components/apps/editor/component/components.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/src/lib/components/apps/editor/component/components.ts b/frontend/src/lib/components/apps/editor/component/components.ts index c3b93c15f7..d6edf45e97 100644 --- a/frontend/src/lib/components/apps/editor/component/components.ts +++ b/frontend/src/lib/components/apps/editor/component/components.ts @@ -2413,12 +2413,7 @@ This is a paragraph. documentationLink: `${documentationBaseUrl}/select`, dims: '2:1-3:1' as AppComponentDimensions, customCss: { - input: { - style: '', - tooltip: - 'https://github.com/rob-balfre/svelte-select/blob/master/docs/theming_variables.md', - class: '' - } + input: { style: '', class: '' } }, initialData: { recomputeIds: true, From a2d3297343338ba0b559481723e64db5f4acf3a7 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Mon, 24 Nov 2025 19:43:14 +0000 Subject: [PATCH 08/32] fix(frontend): improve preprocessor discoverability (#7214) * add tooltip * show payload tooltip * Add preprocessor button * nit * improve preprocessor template * fix add preprocessor * fix oneof wrapping * clean * Use funnel cog icon for preprocessor step * nit --- frontend/src/lib/components/ArgInput.svelte | 2 + .../src/lib/components/QueuePosition.svelte | 2 +- .../src/lib/components/ScriptBuilder.svelte | 7 +- .../flows/content/FlowEditorPanel.svelte | 6 +- .../graph/renderers/nodes/InputNode.svelte | 7 +- .../src/lib/components/icons/FunnelCog.svelte | 50 ++++++++ .../components/triggers/CaptureSection.svelte | 112 +++++++++++++----- .../components/triggers/CaptureTable.svelte | 2 +- frontend/src/lib/script_helpers.ts | 46 +++---- 9 files changed, 178 insertions(+), 56 deletions(-) create mode 100644 frontend/src/lib/components/icons/FunnelCog.svelte diff --git a/frontend/src/lib/components/ArgInput.svelte b/frontend/src/lib/components/ArgInput.svelte index f912fad49f..c46f85410d 100644 --- a/frontend/src/lib/components/ArgInput.svelte +++ b/frontend/src/lib/components/ArgInput.svelte @@ -1049,6 +1049,8 @@ {#if oneOf && oneOf.length >= 2} { oneOfSelected = detail const selectedObjProperties = diff --git a/frontend/src/lib/components/QueuePosition.svelte b/frontend/src/lib/components/QueuePosition.svelte index d9180aa7e8..375942abbc 100644 --- a/frontend/src/lib/components/QueuePosition.svelte +++ b/frontend/src/lib/components/QueuePosition.svelte @@ -87,7 +87,7 @@ {#if queueState} -
+
Queue position: {queueState.position} {#if !minimal} (Waiting for an available worker) diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index df82c244ab..fa817b4058 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -849,7 +849,7 @@ captureOn.set(true) } - function addPreprocessor() { + function addPreprocessor(e?: { detail?: { args: Record } }) { const code = editor?.getCode() if (code) { const preprocessorCode = getPreprocessorFullCode(script.language, false) @@ -865,6 +865,11 @@ } } selectedInputTab = 'preprocessor' + + // Apply provided args to the preprocessor + if (e?.detail?.args && Object.keys(e.detail.args).length > 0) { + args = { ...args, ...e.detail.args } + } } function handleDeployTrigger(trigger: Trigger) { diff --git a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte index f0288e6533..f5ca067eeb 100644 --- a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte +++ b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte @@ -64,7 +64,8 @@ initialPathStore, fakeInitialPath, previewArgs, - flowInputEditorState + flowInputEditorState, + stepsInputArgs } = getContext('FlowEditorContext') const selectedId = $derived(selectionManager.getSelectedId()) @@ -115,10 +116,11 @@ {:else if selectedId === 'Trigger'} { + on:addPreprocessor={async (e) => { await insertNewPreprocessorModule(flowStore, flowStateStore, { language: 'bun' }) + stepsInputArgs.setStepArgs('preprocessor', e.detail.args ?? {}) selectionManager.selectId('preprocessor') }} on:updateSchema={(e) => { diff --git a/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte b/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte index dc76c013b6..705a07b879 100644 --- a/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte +++ b/frontend/src/lib/components/graph/renderers/nodes/InputNode.svelte @@ -12,6 +12,7 @@ import { MessageSquare, DiffIcon } from 'lucide-svelte' import { Button } from '$lib/components/common' import { getGraphContext } from '../../graphContext' + import FunnelCog from '$lib/components/icons/FunnelCog.svelte' interface Props { data: InputN['data'] @@ -71,7 +72,11 @@ }} > {#snippet trigger()} - + {/snippet}
diff --git a/frontend/src/lib/components/icons/FunnelCog.svelte b/frontend/src/lib/components/icons/FunnelCog.svelte new file mode 100644 index 0000000000..12602f6849 --- /dev/null +++ b/frontend/src/lib/components/icons/FunnelCog.svelte @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/lib/components/triggers/CaptureSection.svelte b/frontend/src/lib/components/triggers/CaptureSection.svelte index 366b03dc1a..eebfe3c1a7 100644 --- a/frontend/src/lib/components/triggers/CaptureSection.svelte +++ b/frontend/src/lib/components/triggers/CaptureSection.svelte @@ -14,7 +14,7 @@ import AnimatedButton from '../common/button/AnimatedButton.svelte' import PulseButton from '../common/button/PulseButton.svelte' import Button from '../common/button/Button.svelte' - import { CircleStop, History, Play, Loader2 } from 'lucide-svelte' + import { CircleStop, History, Play, Loader2, ExternalLink } from 'lucide-svelte' import ConnectionIndicator, { type ConnectionInfo } from '../common/alert/ConnectionIndicator.svelte' @@ -67,7 +67,7 @@ const dispatch = createEventDispatcher<{ captureToggle: { disableOnly?: boolean } updateSchema: { payloadData: Record; redirect: boolean; args?: boolean } - addPreprocessor: null + addPreprocessor: { args: Record } | null testWithArgs: Record applyArgs: { kind: 'main' | 'preprocessor'; args: Record } }>() @@ -121,6 +121,7 @@ let lastCaptureId: number | undefined = undefined let displayResult: DisplayResult | undefined = $state(undefined) let toolbarLocation: 'internal' | 'external' | undefined = $state(undefined) + let showRawPayload = $state(false) function selectCapture(capture: Capture) { selectedCapture = capture @@ -225,13 +226,14 @@ } } - function getCapturePayload(capture: Capture) { + function getCapturePayload(capture: Capture | undefined, showRawPayload: boolean) { + if (!capture) return {} let payloadData: any = {} const preprocessor_args = isObject(capture.preprocessor_args) ? capture.preprocessor_args : {} if ('wm_trigger' in preprocessor_args) { // v1 payloadData = - testKind === 'preprocessor' + testKind === 'preprocessor' || showRawPayload ? { ...(typeof capture.main_args === 'object' ? capture.main_args : {}), ...preprocessor_args @@ -239,11 +241,20 @@ : capture.main_args } else { // v2 - payloadData = testKind === 'preprocessor' ? capture.preprocessor_args : capture.main_args + payloadData = + testKind === 'preprocessor' || showRawPayload + ? capture.preprocessor_args + : capture.main_args } return payloadData } + function toggleRawPayload() { + showRawPayload = !showRawPayload + } + + const payloadData = $derived(getCapturePayload(selectedCapture, showRawPayload)) + // Start or stop capture listening based on active state $effect(() => { if (captureInfo.active) { @@ -380,16 +391,16 @@ {#if selectedCapture} {@const SvelteComponent = triggerIconMap[captureType]}
- + Capture {formatDateShort(selectedCapture?.created_at)}
{/if} - {#if selectedCapture} + {#if selectedCapture && !showRawPayload} {@const label = isFlow && testKind === 'main' ? 'Test flow with args' : 'Apply args'} {@const title = isFlow && testKind === 'main' @@ -455,26 +466,73 @@ /> {/if}
-
- {#if isLoadingBigPayload} - - {:else if selectedCapture?.main_args} -
- { - toolbarLocation = detail - }} - /> +
+
+ {#if isLoadingBigPayload} + + {:else if selectedCapture?.main_args} +
+ {#if showRawPayload} + +
+
+ Add a preprocessor to use the raw payload data in the flow. + + Learn more about preprocessors + + +
+
+ +
+
+
+ {/if} + { + toolbarLocation = detail + }} + /> +
+ {:else} +
No captures to show yet.
+ {/if} +
+ + {#if !hasPreprocessor && !isLoadingBigPayload && selectedCapture?.main_args} +
+ {showRawPayload ? '' : 'Need more data about the trigger event?'} +
- {:else} -
No captures to show yet.
{/if}
diff --git a/frontend/src/lib/components/triggers/CaptureTable.svelte b/frontend/src/lib/components/triggers/CaptureTable.svelte index 20f3703921..f6bc1d209f 100644 --- a/frontend/src/lib/components/triggers/CaptureTable.svelte +++ b/frontend/src/lib/components/triggers/CaptureTable.svelte @@ -71,7 +71,7 @@ kind: 'main' | 'preprocessor' args: Record | undefined } - addPreprocessor: null + addPreprocessor: { args: Record } | undefined updateSchema: { payloadData: any redirect: boolean diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index 532c11cab1..58bec208de 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -691,16 +691,21 @@ export const TS_PREPROCESSOR_FLOW_INTRO = `/** * Learn more: https://www.windmill.dev/docs/core_concepts/preprocessors */\n` -export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( - event: - | { +export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor(event: TriggerEvent) { + return { + // return the args to be passed to the runnable + }; +} + +type TriggerEvent = + | { kind: "webhook"; body: any; raw_string: string | null; query: Record; headers: Record; } - | { + | { kind: "http"; body: any; raw_string: string | null; @@ -711,21 +716,21 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( query: Record; headers: Record; } - | { + | { kind: "email"; parsed_email: any; raw_email: string; email_extra_args?: Record; } - | { kind: "websocket"; msg: string; url: string } - | { + | { kind: "websocket"; msg: string; url: string } + | { kind: "kafka"; payload: string; brokers: string[]; topic: string; group_id: string; } - | { + | { kind: "nats"; payload: string; servers: string[]; @@ -735,7 +740,7 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( description?: string; length: number; } - | { + | { kind: "sqs"; msg: string; queue_url: string; @@ -747,7 +752,7 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( { string_value?: string; data_type: string } >; } - | { + | { kind: "mqtt"; payload: string; topic: string; @@ -764,7 +769,7 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( content_type?: string; }; } - | { + | { kind: "gcp"; payload: string; message_id: string; @@ -776,19 +781,14 @@ export const TS_PREPROCESSOR_MODULE_CODE = `export async function preprocessor( publish_time?: string; ack_id?: string; } - | { + | { kind: "postgres"; - transaction_type: "insert" | "update" | "delete", - schema_name: string, - table_name: string, - old_row?: Record, - row: Record - } -) { - return { - // return the args to be passed to the runnable - }; -} + transaction_type: "insert" | "update" | "delete"; + schema_name: string; + table_name: string; + old_row?: Record; + row: Record; + }; ` const PYTHON_INIT_CODE_APPROVAL = `import wmill From dccee1dba08b4c4b170336b3f3e959fbe7bca8ce Mon Sep 17 00:00:00 2001 From: hugocasa Date: Mon, 24 Nov 2025 22:41:05 +0100 Subject: [PATCH 09/32] fix(frontend): forking UI issues (#7215) * fix(frontend): forking UI issues * fix dark mode --- frontend/src/lib/components/Path.svelte | 6 +- .../src/lib/components/ScriptBuilder.svelte | 4 +- .../src/lib/components/ScriptEditor.svelte | 21 ++- .../components/ScriptEditorSkeleton.svelte | 55 ++++++++ .../src/lib/components/TagsToListenTo.svelte | 5 +- .../components/common/table/ScriptRow.svelte | 2 +- .../flows/edit/[...path]/+page.svelte | 7 +- .../(root)/(logged)/run/[...run]/+page.svelte | 9 +- .../(root)/(logged)/scripts/add/+page.svelte | 130 +++++++++++------- 9 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 frontend/src/lib/components/ScriptEditorSkeleton.svelte diff --git a/frontend/src/lib/components/Path.svelte b/frontend/src/lib/components/Path.svelte index 85f9df1ec5..dafd4320af 100644 --- a/frontend/src/lib/components/Path.svelte +++ b/frontend/src/lib/components/Path.svelte @@ -138,7 +138,7 @@ } export async function reset() { - if (path == '' || path == 'u//') { + if (path == '' || path == 'u//' || path?.startsWith('tmp/')) { if ($lastMetaUsed == undefined || $lastMetaUsed.owner != $userStore?.username) { meta = { ownerKind: hideUser ? 'folder' : 'user', @@ -323,12 +323,12 @@ async function initPath() { await tick() - if (path != undefined && path != '') { + if (path != undefined && path != '' && !path?.startsWith('tmp/')) { meta = pathToMeta(path, hideUser) onMetaChange() return } - if (initialPath == undefined || initialPath == '') { + if (initialPath == undefined || initialPath == '' || initialPath?.startsWith('tmp/')) { reset() } else { meta = pathToMeta(initialPath, hideUser) diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index fa817b4058..4b386aa363 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -379,7 +379,7 @@ if (templateScript) { script.content += '\r\n' + templateScript } - scriptEditor?.inferSchema(script.content, language, true) + scriptEditor?.inferSchema(script.content, { nlang: language, resetArgs: true }) if (script.content != editor?.getCode()) { setCode(script.content) } @@ -567,7 +567,7 @@ if (!disableHistoryChange) { history.replaceState(history.state, '', `/scripts/edit/${script.path}`) } - if (stay || script.kind !== 'script' || script.no_main_func) { + if (stay || (script.no_main_func && script.kind !== 'preprocessor')) { script.parent_hash = newHash sendUserToast('Deployed') } else { diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index a9fcdc5cba..cd9356e34b 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -123,6 +123,8 @@ enablePreprocessorSnippet = false }: Props = $props() + let initialArgs = structuredClone($state.snapshot(args)) + $effect.pre(() => { if (schema == undefined) { schema = emptySchema() @@ -269,7 +271,18 @@ }) } - export async function inferSchema(code: string, nlang?: SupportedLanguage, resetArgs = false) { + export async function inferSchema( + code: string, + { + nlang, + resetArgs = false, + applyInitialArgs = false + }: { + nlang?: SupportedLanguage + resetArgs?: boolean + applyInitialArgs?: boolean + } = {} + ) { let nschema = schema ?? emptySchema() try { @@ -297,6 +310,10 @@ if (resetArgs) { args = {} } + if (applyInitialArgs) { + // we reapply initial args as the schema form might have cleared them between mount and the schema inference + args = initialArgs + } schema = nschema } catch (e) { validCode = false @@ -338,7 +355,7 @@ } onMount(() => { - inferSchema(code) + inferSchema(code, { applyInitialArgs: true }) loadPastTests() aiChatManager.saveAndClear() aiChatManager.changeMode(AIMode.SCRIPT) diff --git a/frontend/src/lib/components/ScriptEditorSkeleton.svelte b/frontend/src/lib/components/ScriptEditorSkeleton.svelte new file mode 100644 index 0000000000..031b8c9ee9 --- /dev/null +++ b/frontend/src/lib/components/ScriptEditorSkeleton.svelte @@ -0,0 +1,55 @@ +
+ +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/lib/components/TagsToListenTo.svelte b/frontend/src/lib/components/TagsToListenTo.svelte index 76c7fe15d6..e99c67223b 100644 --- a/frontend/src/lib/components/TagsToListenTo.svelte +++ b/frontend/src/lib/components/TagsToListenTo.svelte @@ -29,6 +29,9 @@ {disabled} class={disabled ? 'border-0' : ''} allowClear={!disabled} - onCreateItem={(c) => worker_tags.push(c)} + onCreateItem={(c) => { + worker_tags.push(c) + dispatch('dirty') + }} createText="Press Enter to use this tag" /> diff --git a/frontend/src/lib/components/common/table/ScriptRow.svelte b/frontend/src/lib/components/common/table/ScriptRow.svelte index 840bac9526..1fa78d86cd 100644 --- a/frontend/src/lib/components/common/table/ScriptRow.svelte +++ b/frontend/src/lib/components/common/table/ScriptRow.svelte @@ -112,7 +112,7 @@ - import { type NewScript, ScriptService, type Script } from '$lib/gen' + import { type NewScript, ScriptService, type ScriptLang } from '$lib/gen' import { page } from '$app/stores' import { defaultScripts, initialArgsStore, workspaceStore } from '$lib/stores' import ScriptBuilder from '$lib/components/ScriptBuilder.svelte' import type { Schema } from '$lib/common' - import { decodeState, emptySchema, emptyString } from '$lib/utils' + import { decodeState, emptySchema, emptyString, sendUserToast } from '$lib/utils' import { goto } from '$lib/navigation' import { replaceState } from '$app/navigation' import UnsavedConfirmationModal from '$lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte' @@ -13,6 +13,13 @@ import type { Trigger } from '$lib/components/triggers/utils' import { get } from 'svelte/store' import { untrack } from 'svelte' + import ScriptEditorSkeleton from '$lib/components/ScriptEditorSkeleton.svelte' + + type Script = NewScript & { + draft_triggers?: Trigger[] + hash?: string + extra_perms?: Record + } // Default let schema: Schema = emptySchema() @@ -20,8 +27,9 @@ const templatePath = $page.url.searchParams.get('template') const hubPath = $page.url.searchParams.get('hub') const showMeta = /true|1/i.test($page.url.searchParams.get('show_meta') ?? '0') + const urlArgs = $page.url.searchParams.get('initial_args') - let initialArgs = get(initialArgsStore) ?? {} + let initialArgs = urlArgs ? decodeState(urlArgs) : (get(initialArgsStore) ?? {}) if (get(initialArgsStore)) $initialArgsStore = undefined const path = $page.url.searchParams.get('path') @@ -40,54 +48,74 @@ } } - function defaultScript() { + function defaultScript(): Script { return { hash: '', path: path ?? '', summary: '', content: '', + description: '', schema: schema, is_template: false, extra_perms: {}, - language: - $defaultScripts?.order?.filter( - (x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x) - )?.[0] ?? 'bun', + language: ($defaultScripts?.order?.filter( + (x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x) + )?.[0] ?? 'bun') as ScriptLang, kind: 'script' } } - let script: NewScript & { draft_triggers: Trigger[] } = $state( - !path && initialState != undefined ? decodeStateAndHandleError(initialState) : defaultScript() + let script: Script | undefined = $state( + templatePath || hubPath + ? undefined + : !path && initialState != undefined + ? decodeStateAndHandleError(initialState) + : defaultScript() ) async function loadTemplate(): Promise { if (templatePath) { - const template = await ScriptService.getScriptByPath({ - workspace: $workspaceStore!, - path: templatePath - }) - - // Only copy the summary if it's not empty - script.summary = !emptyString(template.summary) ? `Copy of ${template.summary}` : '' - script.description = template.description - script.content = template.content - script.schema = template.schema - script.language = template.language - scriptBuilder?.setCode(script.content) + try { + const template = await ScriptService.getScriptByPath({ + workspace: $workspaceStore!, + path: templatePath + }) + script = { + ...defaultScript(), + summary: !emptyString(template.summary) ? `Copy of ${template.summary}` : '', + description: template.description, + content: template.content, + schema: template.schema, + language: template.language, + path: template.path + '_fork' + } + } catch (err) { + script = defaultScript() + console.error('Error loading template', err) + sendUserToast('Error loading template: ' + err.message, true) + } } } async function loadHub(): Promise { if (hubPath) { - const { content, language, summary } = await ScriptService.getHubScriptByPath({ - path: hubPath - }) - script.description = `Fork of ${hubPath}` - script.content = replaceScriptPlaceholderWithItsValues(hubPath, content) - script.summary = summary ?? '' - script.language = language as Script['language'] - scriptBuilder?.setCode(script.content) + try { + const { content, language, summary } = await ScriptService.getHubScriptByPath({ + path: hubPath + }) + script = { + ...defaultScript(), + description: `Fork of ${hubPath}`, + content: replaceScriptPlaceholderWithItsValues(hubPath, content), + summary: summary ?? '', + language: language as Script['language'], + path: hubPath + '_fork' + } + } catch (err) { + script = defaultScript() + console.error('Error loading script from hub', err) + sendUserToast('Error loading script from hub: ' + err.message, true) + } } } @@ -100,22 +128,26 @@ }) - { - goto(`/scripts/get/${e.hash}?workspace=${$workspaceStore}`) - }} - onSaveInitial={(e) => { - goto(`/scripts/edit/${e.path}`) - }} - searchParams={$page.url.searchParams} - bind:script - {showMeta} - replaceStateFn={(path) => replaceState(path, $page.state)} -> - - +{#if script} + { + goto(`/scripts/get/${e.hash}?workspace=${$workspaceStore}`) + }} + onSaveInitial={(e) => { + goto(`/scripts/edit/${e.path}`) + }} + searchParams={$page.url.searchParams} + bind:script + {showMeta} + replaceStateFn={(path) => replaceState(path, $page.state)} + > + + +{:else} + +{/if} From e87f81470904578467f42598cfce5fad2249f131 Mon Sep 17 00:00:00 2001 From: hugocasa Date: Tue, 25 Nov 2025 12:02:36 +0100 Subject: [PATCH 10/32] fix(frontend): loading saved/history inputs when json view is on (#7217) --- .../routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte index 76f22642bd..5f88a212eb 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte @@ -783,6 +783,9 @@ on:selected_args={(e) => { const nargs = JSON.parse(JSON.stringify(e.detail)) args = nargs + if (jsonView) { + runForm?.setCode(JSON.stringify(args ?? {}, null, '\t')) + } }} /> {/if} From 897faf085b49ada0648594797cfe627decb50952 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 25 Nov 2025 11:11:14 +0000 Subject: [PATCH 11/32] fix: list scripts without 1000 limits --- backend/windmill-api/src/scripts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index a772100a50..d5d3e654a9 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -41,11 +41,11 @@ use windmill_audit::ActionKind; use windmill_worker::{process_relative_imports, scoped_dependency_map::ScopedDependencyMap}; use windmill_common::{ - assets::{clear_asset_usage, insert_asset_usage, AssetUsageKind, AssetWithAltAccessType}, + assets::{AssetUsageKind, AssetWithAltAccessType, clear_asset_usage, insert_asset_usage}, error::to_anyhow, s3_helpers::upload_artifact_to_store, scripts::hash_script, - utils::WarnAfterExt, + utils::{WarnAfterExt, paginate_without_limits}, worker::{CLOUD_HOSTED, MIN_VERSION_SUPPORTS_DEBOUNCING}, }; @@ -61,7 +61,7 @@ use windmill_common::{ }, users::username_to_permissioned_as, utils::{ - not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath, + not_found_if_none, query_elems_from_hub, require_admin, Pagination, StripPath, }, worker::to_raw_value, HUB_BASE_URL, @@ -193,7 +193,7 @@ async fn list_search_scripts( ) -> JsonResult> { let mut tx = user_db.begin(&authed).await?; #[cfg(feature = "enterprise")] - let n = 1000; + let n = 10000; #[cfg(not(feature = "enterprise"))] let n = 10; @@ -219,7 +219,7 @@ async fn list_scripts( Query(pagination): Query, Query(lq): Query, ) -> JsonResult> { - let (per_page, offset) = paginate(pagination); + let (per_page, offset) = paginate_without_limits(pagination); let mut sqlb = SqlBuilder::select_from("script as o") .fields(&[ "hash", From de7739a3ee7ef76a8eb4fe6570ef0bdfbdb92293 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 25 Nov 2025 12:12:49 +0000 Subject: [PATCH 12/32] fix(cli): handle better public apps --- cli/src/commands/app/apps.ts | 11 ++++++++--- cli/src/commands/sync/sync.ts | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cli/src/commands/app/apps.ts b/cli/src/commands/app/apps.ts index 1c6baceda2..0fefd7afbc 100644 --- a/cli/src/commands/app/apps.ts +++ b/cli/src/commands/app/apps.ts @@ -18,6 +18,7 @@ import { readInlinePathSync } from "../../utils/utils.ts"; export interface AppFile { value: any; + public?: boolean; summary: string; policy: Policy; } @@ -45,6 +46,10 @@ export async function pushApp( } catch { //ignore } + if (app?.["policy"]?.["execution_mode"] == "anonymous") { + app.public = true; + } + // console.log(app); if (app) { app.policy = undefined; } @@ -80,7 +85,7 @@ export async function pushApp( } replaceInlineScripts(localApp.value); - await generatingPolicy(localApp, remotePath); + await generatingPolicy(localApp, remotePath, localApp?.["public"] ?? false); if (app) { if (isSuperset(localApp, app)) { log.info(colors.green(`App ${remotePath} is up to date`)); @@ -109,11 +114,11 @@ export async function pushApp( } } -async function generatingPolicy(app: any, path: string) { +async function generatingPolicy(app: any, path: string, publicApp: boolean) { log.info(colors.gray(`Generating fresh policy for app ${path}...`)); try { app.policy = await windmillUtils.updatePolicy(app.value, undefined); - app.policy.execution_mode = "publisher"; + app.policy.execution_mode = publicApp ? "anonymous" : "publisher"; } catch (e) { log.error(colors.red(`Error generating policy for app ${path}: ${e}`)); throw e; diff --git a/cli/src/commands/sync/sync.ts b/cli/src/commands/sync/sync.ts index b0e2b74682..d145b03490 100644 --- a/cli/src/commands/sync/sync.ts +++ b/cli/src/commands/sync/sync.ts @@ -415,6 +415,9 @@ function ZipFSElement( }; } + if (app?.["policy"]?.["execution_mode"] == "anonymous") { + app.public = true; + } app.policy = undefined; yield { isDirectory: false, From c37dde096c301a502c6ff2c570b91153a5717fcd Mon Sep 17 00:00:00 2001 From: Guilhem Date: Tue, 25 Nov 2025 12:14:19 +0000 Subject: [PATCH 13/32] fix(frontend): show trigger table when no trigger selected (#7219) * improve triggers pannel * nit * nit --- .../DraftTriggersConfirmationModal.svelte | 19 +- .../details/DetailPageHeader.svelte | 2 +- .../lib/components/graph/FlowGraphV2.svelte | 2 +- .../renderers/triggers/TriggersBadge.svelte | 8 +- .../triggers/DeleteTriggerButton.svelte | 6 +- .../triggers/TriggerEditorToolbar.svelte | 4 +- .../components/triggers/TriggerLabel.svelte | 19 +- .../components/triggers/TriggersEditor.svelte | 219 ++++++++++-------- .../components/triggers/TriggersTable.svelte | 12 +- .../triggers/TriggersWrapper.svelte | 6 +- .../(logged)/flows/get/[...path]/+page.svelte | 20 +- .../scripts/get/[...hash]/+page.svelte | 10 +- 12 files changed, 166 insertions(+), 161 deletions(-) diff --git a/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte b/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte index cf43ab8672..e8fec0b907 100644 --- a/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/DraftTriggersConfirmationModal.svelte @@ -10,6 +10,7 @@ import ToggleButtonGroup from '../toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '../toggleButton-v2/ToggleButton.svelte' import { userStore } from '$lib/stores' + import Badge from '../badge/Badge.svelte' interface Props { open?: boolean @@ -132,32 +133,22 @@ value={'discard'} {item} small - class="data-[state=on]:text-white data-[state=on]:bg-red-400 w-[54px] justify-center" + class="data-[state=on]:text-white data-[state=on]:bg-red-400 justify-center" /> {/snippet}
{:else if permission === 'admin-only'} -
- Admin only -
+ Admin only {:else if permission === 'invalid-config'} -
- Invalid config -
+ Invalid config {/if} diff --git a/frontend/src/lib/components/details/DetailPageHeader.svelte b/frontend/src/lib/components/details/DetailPageHeader.svelte index c8185e2746..818c3ea76d 100644 --- a/frontend/src/lib/components/details/DetailPageHeader.svelte +++ b/frontend/src/lib/components/details/DetailPageHeader.svelte @@ -58,7 +58,7 @@
diff --git a/frontend/src/lib/components/graph/FlowGraphV2.svelte b/frontend/src/lib/components/graph/FlowGraphV2.svelte index 9be2534b9f..7664bae49a 100644 --- a/frontend/src/lib/components/graph/FlowGraphV2.svelte +++ b/frontend/src/lib/components/graph/FlowGraphV2.svelte @@ -397,7 +397,7 @@ }, select: (modId) => { // AI tools are not selectable by the flow. Selection has to be refactored to be simplier. - if (nodes.find((n) => n.data?.moduleId === modId)?.type === 'aiTool') { + if (nodes.find((n) => n.data?.moduleId === modId)?.type === 'aiTool' || modId === 'Trigger') { selectionManager.selectId(modId) } if (!notSelectable) { diff --git a/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte b/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte index 048f39d9c4..d064cedf77 100644 --- a/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte +++ b/frontend/src/lib/components/graph/renderers/triggers/TriggersBadge.svelte @@ -246,10 +246,10 @@ aiId={`trigger-button-${type}`} aiDescription={`Trigger button for ${type}`} class={twMerge( - 'hover:bg-surface-hover rounded-md shadow-sm text-xs relative center-center cursor-pointer bg-slate-100 dark:bg-slate-700', - 'dark:outline dark:outline-1 outline-tertiary/20 group', - isSelected ? 'outline-tertiary outline' : '', - small ? 'w-[23px] h-[23px] outline-[1.5px]' : 'p-2 outline-[2px]' + 'hover:bg-surface-hover rounded-md text-xs relative center-center cursor-pointer border border-border-light', + 'group', + isSelected ? 'bg-surface-accent-selected text-accent border-border-selected' : '', + small ? 'w-[23px] h-[23px]' : 'p-2' )} on:click={(e) => { e.stopPropagation() diff --git a/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte b/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte index 1b4d6f8954..b7fed3d6d0 100644 --- a/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte +++ b/frontend/src/lib/components/triggers/DeleteTriggerButton.svelte @@ -39,12 +39,12 @@
- {/if} - + {#if triggersState.selectedTrigger}
+ + {#if !useVerticalTriggerBar} +
+ +
+ {:else} +
+ +
+ {/if} + +
+ {#if loading} +
+ {:else} + {#key [renderCount, triggersState.selectedTriggerIndex].join('-')} +
+ { + deleteTrigger(triggersState.selectedTriggerIndex) + }} + onUpdate={(path) => { + handleUpdate(triggersState.selectedTriggerIndex, path) + }} + onConfigChange={(cfg, canSave, updated) => { + if (updated) { + handleUpdateDraftConfig(triggersState.selectedTriggerIndex, cfg, canSave) + } + }} + onCaptureConfigChange={(cfg, isValidConfig) => { + config = cfg + isValid = isValidConfig + }} + onReset={() => { + handleResetDraft(triggersState.selectedTriggerIndex) + }} + onEmailDomain={(domain) => { + emailDomain = domain + }} + /> +
+ {/key} + {/if} +
+
+ {:else} + +
{#if loading}
- {:else if triggersState.selectedTrigger} - {#key [renderCount, triggersState.selectedTriggerIndex].join('-')} -
- { - deleteTrigger(triggersState.selectedTriggerIndex) - }} - onUpdate={(path) => { - handleUpdate(triggersState.selectedTriggerIndex, path) - }} - onConfigChange={(cfg, canSave, updated) => { - if (updated) { - handleUpdateDraftConfig(triggersState.selectedTriggerIndex, cfg, canSave) - } - }} - onCaptureConfigChange={(cfg, isValidConfig) => { - config = cfg - isValid = isValidConfig - }} - onReset={() => { - handleResetDraft(triggersState.selectedTriggerIndex) - }} - onEmailDomain={(domain) => { - emailDomain = domain - }} - /> -
- {/key} {:else} - {`Select a trigger from the ${useVerticalTriggerBar ? 'left toolbar' : 'table'} or create a new one`} +
+ +
{/if}
-
+ {/if} {#if !cloudDisabled && triggersState.selectedTrigger && triggersState.selectedTrigger.type !== 'schedule' && triggersState.selectedTrigger.type != 'poll' && !noCapture} {@const captureKind = triggersState.selectedTrigger diff --git a/frontend/src/lib/components/triggers/TriggersTable.svelte b/frontend/src/lib/components/triggers/TriggersTable.svelte index 33588cb9d8..827395bcb8 100644 --- a/frontend/src/lib/components/triggers/TriggersTable.svelte +++ b/frontend/src/lib/components/triggers/TriggersTable.svelte @@ -59,8 +59,11 @@ {@const SvelteComponent = triggerIconMap[trigger.type]} onSelect?.(index)} use:triggerableByAI={{ @@ -71,10 +74,7 @@ >
- + {#if trigger.isPrimary} diff --git a/frontend/src/lib/components/triggers/TriggersWrapper.svelte b/frontend/src/lib/components/triggers/TriggersWrapper.svelte index 5030069f10..973931ceb2 100644 --- a/frontend/src/lib/components/triggers/TriggersWrapper.svelte +++ b/frontend/src/lib/components/triggers/TriggersWrapper.svelte @@ -16,7 +16,6 @@ import ClipboardPanel from '../details/ClipboardPanel.svelte' import CliHelpBox from '../CliHelpBox.svelte' import TriggerLabel from './TriggerLabel.svelte' - import { twMerge } from 'tailwind-merge' interface Props { selectedTrigger: Trigger @@ -178,10 +177,7 @@ {#snippet customLabel()} {@const IconComponent = triggerIconMap[selectedTrigger.type]}
- +
{/snippet} diff --git a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte index 43eeab456b..55c0b4f775 100644 --- a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte @@ -33,10 +33,10 @@ GitFork, Play, History, - Columns, Pen, Eye, - HistoryIcon + HistoryIcon, + LayoutDashboard } from 'lucide-svelte' import DetailPageHeader from '$lib/components/details/DetailPageHeader.svelte' @@ -238,7 +238,7 @@ buttonProps: { href: `${base}/flows/add?template=${flow.path}`, variant: 'subtle', - size: 'xs', + unifiedSize: 'md', startIcon: GitFork } }) @@ -252,7 +252,7 @@ label: `Runs`, buttonProps: { href: `${base}/runs/${flow.path}`, - size: 'xs', + unifiedSize: 'md', variant: 'subtle', startIcon: Play } @@ -262,7 +262,7 @@ label: `History`, buttonProps: { onClick: () => flowHistory?.open(), - size: 'xs', + unifiedSize: 'md', variant: 'subtle', startIcon: History } @@ -281,9 +281,9 @@ $importStore = JSON.parse(JSON.stringify(app)) await goto('/apps/add?nodraft=true') }, - size: 'xs', - variant: 'accent', - startIcon: Columns + unifiedSize: 'md', + variant: 'subtle', + startIcon: LayoutDashboard } }) @@ -291,8 +291,8 @@ label: 'Edit', buttonProps: { href: `${base}/flows/edit/${path}?nodraft=true`, - variant: 'accent-secondary', - size: 'xs', + variant: 'accent', + unifiedSize: 'md', disabled: !can_write, startIcon: Pen } diff --git a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte index 5f88a212eb..0dbe481e9f 100644 --- a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte @@ -58,10 +58,10 @@ Pen, ChevronUpSquare, Share, - Table2, Trash, Play, - ClipboardCopy + ClipboardCopy, + LayoutDashboard } from 'lucide-svelte' import { SCRIPT_VIEW_SHOW_PUBLISH_TO_HUB } from '$lib/consts' import { scriptToHubUrl } from '$lib/hub' @@ -339,8 +339,8 @@ }, unifiedSize: 'md', - variant: 'accent', - startIcon: Table2 + variant: 'subtle', + startIcon: LayoutDashboard } }) @@ -367,7 +367,7 @@ }`, unifiedSize: 'md', startIcon: Pen, - variant: 'accent-secondary', + variant: 'accent', disabled: !can_write } }) From 2388e38a9c27bccc2ce6888b5c4985ee5862590e Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 25 Nov 2025 13:17:34 +0100 Subject: [PATCH 14/32] chore(main): release 1.584.0 (#7213) * chore(main): release 1.584.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> --- CHANGELOG.md | 17 +++++ backend/Cargo.lock | 66 +++++++++---------- backend/Cargo.toml | 4 +- backend/windmill-api/openapi.yaml | 2 +- benchmarks/lib.ts | 2 +- cli/src/main.ts | 2 +- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- lsp/Pipfile | 4 +- openflow.openapi.yaml | 2 +- .../WindmillClient/WindmillClient.psd1 | 2 +- python-client/wmill/pyproject.toml | 2 +- python-client/wmill_pg/pyproject.toml | 2 +- typescript-client/jsr.json | 2 +- typescript-client/package.json | 2 +- version.txt | 2 +- 16 files changed, 67 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb26b908fe..d65463af95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [1.584.0](https://github.com/windmill-labs/windmill/compare/v1.583.3...v1.584.0) (2025-11-25) + + +### Features + +* **app:** add chat component ([#7199](https://github.com/windmill-labs/windmill/issues/7199)) ([c47669b](https://github.com/windmill-labs/windmill/commit/c47669be0bffb0821afe9d4182cc071cb3b675f0)) + + +### Bug Fixes + +* **cli:** handle better public apps ([de7739a](https://github.com/windmill-labs/windmill/commit/de7739a3ee7ef76a8eb4fe6570ef0bdfbdb92293)) +* **frontend:** forking UI issues ([#7215](https://github.com/windmill-labs/windmill/issues/7215)) ([dccee1d](https://github.com/windmill-labs/windmill/commit/dccee1dba08b4c4b170336b3f3e959fbe7bca8ce)) +* **frontend:** improve preprocessor discoverability ([#7214](https://github.com/windmill-labs/windmill/issues/7214)) ([a2d3297](https://github.com/windmill-labs/windmill/commit/a2d3297343338ba0b559481723e64db5f4acf3a7)) +* **frontend:** loading saved/history inputs when json view is on ([#7217](https://github.com/windmill-labs/windmill/issues/7217)) ([e87f814](https://github.com/windmill-labs/windmill/commit/e87f81470904578467f42598cfce5fad2249f131)) +* **frontend:** show trigger table when no trigger selected ([#7219](https://github.com/windmill-labs/windmill/issues/7219)) ([c37dde0](https://github.com/windmill-labs/windmill/commit/c37dde096c301a502c6ff2c570b91153a5717fcd)) +* list scripts without 1000 limits ([897faf0](https://github.com/windmill-labs/windmill/commit/897faf085b49ada0648594797cfe627decb50952)) + ## [1.583.3](https://github.com/windmill-labs/windmill/compare/v1.583.2...v1.583.3) (2025-11-24) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index eaabb783ab..cce1bb1039 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -14082,9 +14082,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" dependencies = [ "async-compression", "base64 0.22.1", @@ -15210,7 +15210,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "aws-sdk-config", @@ -15272,7 +15272,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "argon2", @@ -15393,7 +15393,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.583.3" +version = "1.584.0" dependencies = [ "base64 0.22.1", "chrono", @@ -15408,7 +15408,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.583.3" +version = "1.584.0" dependencies = [ "chrono", "lazy_static", @@ -15422,7 +15422,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "axum", @@ -15441,7 +15441,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "async-recursion", @@ -15530,7 +15530,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.583.3" +version = "1.584.0" dependencies = [ "regex", "serde", @@ -15545,7 +15545,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "bytes", @@ -15569,7 +15569,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.583.3" +version = "1.584.0" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -15581,7 +15581,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.583.3" +version = "1.584.0" dependencies = [ "convert_case 0.6.0", "serde", @@ -15590,7 +15590,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "lazy_static", @@ -15602,7 +15602,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "serde_json", @@ -15614,7 +15614,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "gosyn", @@ -15626,7 +15626,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "lazy_static", @@ -15638,7 +15638,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "serde_json", @@ -15650,7 +15650,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "nu-parser", @@ -15661,7 +15661,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15672,7 +15672,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15684,7 +15684,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "async-recursion", @@ -15707,7 +15707,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "lazy_static", @@ -15721,7 +15721,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15738,7 +15738,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "lazy_static", @@ -15752,7 +15752,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "lazy_static", @@ -15770,7 +15770,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "serde", @@ -15781,7 +15781,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "async-recursion", @@ -15818,7 +15818,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.583.3" +version = "1.584.0" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15828,7 +15828,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.583.3" +version = "1.584.0" dependencies = [ "anyhow", "async-once-cell", @@ -16625,18 +16625,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 30d36d0c09..d533d32549 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.583.3" +version = "1.584.0" authors.workspace = true edition.workspace = true @@ -33,7 +33,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.583.3" +version = "1.584.0" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 49d85ec411..139c6f325a 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.583.3 + version: 1.584.0 title: Windmill API contact: diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index 3a9f64ee6b..5dc61d56a7 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -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.583.3"; +export const VERSION = "v1.584.0"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/src/main.ts b/cli/src/main.ts index f45ca3607e..4430410890 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.583.3"; +export const VERSION = "1.584.0"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8dc67ac1c6..14868d1907 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.583.3", + "version": "1.584.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.583.3", + "version": "1.584.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 202b2f17c3..58a5be9fdb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.583.3", + "version": "1.584.0", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/lsp/Pipfile b/lsp/Pipfile index ef9fbe6a18..a535d7580a 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.583.3" -wmill_pg = ">=1.583.3" +wmill = ">=1.584.0" +wmill_pg = ">=1.584.0" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 5145d2884f..b724c0acc9 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.583.3 + version: 1.584.0 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index 9d17deaa98..fa0d0e6afa 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.583.3' + ModuleVersion = '1.584.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 10af1ba2c2..4a9cabadc7 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.583.3" +version = "1.584.0" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index f7824560f2..7b9653640e 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.583.3" +version = "1.584.0" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 30478fca0b..f4bfe59424 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.583.3", + "version": "1.584.0", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index b734e93d31..bfe2a641b8 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.583.3", + "version": "1.584.0", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index f511ac6fe7..a224cb38e3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.583.3 +1.584.0 From 79a0d3edc9e7d3a18708bc92459530e313a00ba6 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Tue, 25 Nov 2025 15:56:24 +0000 Subject: [PATCH 15/32] add tip to triggers pannel (#7220) * improve triggers pannel * nit * nit * improve placement and transition * Add tip * stop input selection when adding a preprocessor --- .../flows/map/InsertModuleButton.svelte | 2 +- .../triggers/AddTriggersButton.svelte | 2 +- .../components/triggers/TriggersEditor.svelte | 181 ++++++++++-------- .../components/triggers/TriggersTable.svelte | 12 +- 4 files changed, 104 insertions(+), 93 deletions(-) diff --git a/frontend/src/lib/components/flows/map/InsertModuleButton.svelte b/frontend/src/lib/components/flows/map/InsertModuleButton.svelte index 43068966bf..9645ec7422 100644 --- a/frontend/src/lib/components/flows/map/InsertModuleButton.svelte +++ b/frontend/src/lib/components/flows/map/InsertModuleButton.svelte @@ -11,7 +11,7 @@ let { Icon = Plus, title, id }: Props = $props() -
- {/if} - +
+ + {#if !useVerticalTriggerBar || !triggersState.selectedTrigger}
+ + {#if leftPaneWidth <= 800 && !triggersState.selectedTrigger} +
+ {@render TriggerInfo()} +
+ {/if} +
+ {:else} +
+ +
+ {/if} + + {#if triggersState.selectedTrigger} +
{#if loading} @@ -401,35 +405,10 @@ {/key} {/if}
-
- {:else} - -
- {#if loading} -
- {:else} -
- -
- {/if} -
- {/if} + {:else if leftPaneWidth > 800} + {@render TriggerInfo(true)} + {/if} +
{#if !cloudDisabled && triggersState.selectedTrigger && triggersState.selectedTrigger.type !== 'schedule' && triggersState.selectedTrigger.type != 'poll' && !noCapture} {@const captureKind = triggersState.selectedTrigger @@ -460,3 +439,35 @@ + +{#snippet TriggerInfo(margin: boolean = false)} +
+
+ +
+
+ Triggers automatically run your flow when events + happen. Select one to configure it or create a new one. + Learn more +
+
    +
  • + + Default triggers: Webhooks, email, CLI - always exist, can't be disabled +
  • +
  • + + Additional triggers: Setup advanced triggers, like HTTP routes, database changes, + message queues, cloud events, and more +
  • +
+
+
+
+{/snippet} diff --git a/frontend/src/lib/components/triggers/TriggersTable.svelte b/frontend/src/lib/components/triggers/TriggersTable.svelte index 827395bcb8..62da1bce4f 100644 --- a/frontend/src/lib/components/triggers/TriggersTable.svelte +++ b/frontend/src/lib/components/triggers/TriggersTable.svelte @@ -39,15 +39,15 @@
-
+
@@ -59,7 +59,7 @@ {@const SvelteComponent = triggerIconMap[trigger.type]} onSelect?.(index) }} > - +
- + {#if trigger.isPrimary} From 93c34c6d769dd56da02064c0abdaa060efe0259d Mon Sep 17 00:00:00 2001 From: hugocasa Date: Tue, 25 Nov 2025 17:25:34 +0100 Subject: [PATCH 16/32] feat: flow for loop squashing (#7107) * feat: flow for loop optimization * fix: make dedicated flows work with flow nodes * fix: transform dedicated inputs + better error handling + differentiate squash from same worker * fix builds * fix build * fix build * make dedicated worker private * update ee ref * frontend nits * nit * add trace to dedicated worker * update ee ref * Update ee-repo-ref.txt --------- Co-authored-by: windmill-internal-app[bot] --- backend/ee-repo-ref.txt | 2 +- backend/src/monitor.rs | 14 +- backend/tests/worker.rs | 2 + backend/windmill-api/src/flows.rs | 1 + backend/windmill-common/src/flows.rs | 7 + backend/windmill-queue/src/jobs.rs | 80 +- backend/windmill-queue/src/lib.rs | 2 +- backend/windmill-worker/src/ai/tools.rs | 4 +- backend/windmill-worker/src/bun_executor.rs | 40 +- .../windmill-worker/src/dedicated_worker.rs | 759 ------------------ .../src/dedicated_worker_oss.rs | 26 + backend/windmill-worker/src/deno_executor.rs | 15 +- backend/windmill-worker/src/lib.rs | 6 +- .../windmill-worker/src/python_executor.rs | 22 +- .../windmill-worker/src/result_processor.rs | 37 +- backend/windmill-worker/src/worker.rs | 239 ++++-- backend/windmill-worker/src/worker_flow.rs | 103 ++- .../windmill-worker/src/worker_lockfiles.rs | 5 +- .../lib/components/FlowGraphViewerStep.svelte | 4 +- .../components/flows/content/FlowLoop.svelte | 29 + .../flows/content/FlowWhileLoop.svelte | 31 +- .../lib/components/flows/map/MapItem.svelte | 2 +- openflow.openapi.yaml | 4 + 23 files changed, 548 insertions(+), 886 deletions(-) delete mode 100644 backend/windmill-worker/src/dedicated_worker.rs create mode 100644 backend/windmill-worker/src/dedicated_worker_oss.rs diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index ee9c8abbc4..bc6e0fecec 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -1de62d3f0901aac6ef9ddd7595e1032be56b1938 \ No newline at end of file +f9434efa127dadb0a04c87d6fc368cc289d93501 diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index eaf83c2e4c..d85f5f3d58 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -2316,13 +2316,14 @@ async fn handle_zombie_jobs(db: &Pool, base_internal_url: &str, node_n ); let error_message = format!( - "Job timed out after no ping from job since {} (ZOMBIE_JOB_TIMEOUT: {}, reason: {:?}).\nThis likely means that the job died on worker {}, OOM are a common reason for worker crashes.\nCheck the workers around the time of the last ping and the exit code if any.", - job.last_ping.unwrap_or_default(), - *ZOMBIE_JOB_TIMEOUT, - error_kind.to_string(), - job.worker.clone().unwrap_or_default(), - ); + "Job timed out after no ping from job since {} (ZOMBIE_JOB_TIMEOUT: {}, reason: {:?}).\nThis likely means that the job died on worker {}, OOM are a common reason for worker crashes.\nCheck the workers around the time of the last ping and the exit code if any.", + job.last_ping.unwrap_or_default(), + *ZOMBIE_JOB_TIMEOUT, + error_kind.to_string(), + job.worker.clone().unwrap_or_default(), + ); let memory_peak = job.memory_peak.unwrap_or(0); + let (_, killpill_rx_never_used) = KillpillSender::new(1); let _ = handle_job_error( db, &client, @@ -2335,6 +2336,7 @@ async fn handle_zombie_jobs(db: &Pool, base_internal_url: &str, node_n "", node_name, send_result_never_used, + &killpill_rx_never_used, #[cfg(feature = "benchmark")] &mut windmill_common::bench::BenchmarkIter::new(), ) diff --git a/backend/tests/worker.rs b/backend/tests/worker.rs index 0a92dfc74d..bb18d6e397 100644 --- a/backend/tests/worker.rs +++ b/backend/tests/worker.rs @@ -217,6 +217,7 @@ async fn test_deno_flow(db: Pool) -> anyhow::Result<()> { iterator: InputTransform::Javascript { expr: "result".to_string() }, skip_failures: false, parallel: false, + squash: None, parallelism: None, modules: vec![FlowModule { id: "c".to_string(), @@ -396,6 +397,7 @@ async fn test_deno_flow_same_worker(db: Pool) -> anyhow::Result<()> { iterator: InputTransform::Static { value: windmill_common::worker::to_raw_value(&[1, 2, 3]) }, skip_failures: false, parallel: false, + squash: None, parallelism: None, modules: vec![ FlowModule { diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index 2a75045f9f..98130e2d2d 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -1583,6 +1583,7 @@ mod tests { skip_failures: true, parallel: false, parallelism: None, + squash: None, }), stop_after_if: Some(StopAfterIf { expr: "previous.isEmpty()".to_string(), diff --git a/backend/windmill-common/src/flows.rs b/backend/windmill-common/src/flows.rs index 41e02b7ee8..104f99b301 100644 --- a/backend/windmill-common/src/flows.rs +++ b/backend/windmill-common/src/flows.rs @@ -869,6 +869,8 @@ pub enum FlowModuleValue { parallel: bool, #[serde(skip_serializing_if = "Option::is_none")] parallelism: Option, + #[serde(skip_serializing_if = "Option::is_none")] + squash: Option, }, /// While loop node @@ -878,6 +880,8 @@ pub enum FlowModuleValue { modules_node: Option, #[serde(default = "default_false")] skip_failures: bool, + #[serde(skip_serializing_if = "Option::is_none")] + squash: Option, }, /// Branch-one node @@ -989,6 +993,7 @@ struct UntaggedFlowModuleValue { assets: Option>, tools: Option>, pass_flow_input_directly: Option, + squash: Option, } impl<'de> Deserialize<'de> for FlowModuleValue { @@ -1027,6 +1032,7 @@ impl<'de> Deserialize<'de> for FlowModuleValue { skip_failures: untagged.skip_failures.unwrap_or(true), parallel: untagged.parallel.unwrap_or(false), parallelism: untagged.parallelism, + squash: untagged.squash, }), "whileloopflow" => Ok(FlowModuleValue::WhileloopFlow { modules: untagged @@ -1034,6 +1040,7 @@ impl<'de> Deserialize<'de> for FlowModuleValue { .ok_or_else(|| serde::de::Error::missing_field("modules"))?, modules_node: untagged.modules_node, skip_failures: untagged.skip_failures.unwrap_or(false), + squash: untagged.squash, }), "branchone" => Ok(FlowModuleValue::BranchOne { branches: untagged diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index c050d56659..cc29b94f1b 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -24,6 +24,9 @@ use serde::{ser::SerializeMap, Serialize}; use serde_json::{json, value::RawValue}; use sqlx::{types::Json, Pool, Postgres, Transaction}; use sqlx::{Encode, PgExecutor}; +use tokio::sync::mpsc::Sender; +use tokio::sync::oneshot; +use tokio::task::JoinHandle; use tokio::{sync::RwLock, time::sleep}; use ulid::Ulid; use uuid::Uuid; @@ -137,7 +140,7 @@ pub struct CanceledBy { pub reason: Option, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct JobCompleted { pub job: MiniCompletedJob, pub preprocessed_args: Option>>, @@ -151,6 +154,10 @@ pub struct JobCompleted { pub duration: Option, pub has_stream: Option, pub from_cache: Option, + #[serde(skip)] + pub flow_runners: Option>, + #[serde(skip)] + pub done_tx: Option>, } pub async fn cancel_single_job<'c>( @@ -2271,6 +2278,8 @@ pub struct JobAndPerms { pub parent_runnable_path: Option, pub token: String, pub precomputed_agent_info: Option, + #[serde(skip)] + pub flow_runners: Option>, } impl PulledJob { pub async fn get_job_and_perms(self, db: &DB) -> JobAndPerms { @@ -2302,6 +2311,7 @@ impl PulledJob { parent_runnable_path: self.parent_runnable_path, token, precomputed_agent_info: None, + flow_runners: None, } } } @@ -2492,6 +2502,8 @@ impl PulledJobResult { duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }), ), PulledJobResult { job: Some(job), error_while_preprocessing: Some(e), .. } => Err( @@ -2511,6 +2523,8 @@ impl PulledJobResult { duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }), ), PulledJobResult { job, .. } => Ok(job), @@ -5715,10 +5729,74 @@ async fn restarted_flows_resolution( )) } + + +// Wrapper struct to send both job and optional flow_runners to dedicated workers +pub struct DedicatedWorkerJob { + pub job: Arc, + pub flow_runners: Option>, + pub done_tx: Option>, +} + +#[derive(Debug)] +pub struct FlowRunners { + pub runners: HashMap>, + pub handles: Vec>, + pub job_id: Uuid, +} + +impl Drop for FlowRunners { + fn drop(&mut self) { + let total_runners = self.handles.len(); + tracing::info!("dropping {} flow runners for job {}", total_runners, self.job_id); + + // First, drop all senders to signal workers to stop gracefully + self.runners.clear(); + + // Spawn a background task to wait with timeout and abort if needed + let handles = std::mem::take(&mut self.handles); + let job_id = self.job_id; + + tokio::spawn(async move { + // Extract abort handles before consuming the join handles + let abort_handles: Vec<_> = handles.iter().map(|h| h.abort_handle()).collect(); + + // Wait up to 5 seconds for natural termination + let timeout_result = tokio::time::timeout( + tokio::time::Duration::from_secs(5), + futures::future::join_all(handles) + ).await; + + match timeout_result { + Ok(_) => { + tracing::info!("all {} flow runners for job {} terminated gracefully", total_runners, job_id); + } + Err(_) => { + // Timeout reached, abort only the handles that haven't finished + let mut aborted = 0; + for abort_handle in abort_handles { + if !abort_handle.is_finished() { + abort_handle.abort(); + aborted += 1; + } + } + let graceful = total_runners - aborted; + tracing::warn!( + "flow runners for job {}: {} terminated gracefully, {} aborted after 5s timeout", + job_id, graceful, aborted + ); + } + } + }); + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct SameWorkerPayload { pub job_id: Uuid, pub recoverable: bool, + #[serde(skip)] + pub flow_runners: Option>, } pub async fn get_same_worker_job( diff --git a/backend/windmill-queue/src/lib.rs b/backend/windmill-queue/src/lib.rs index 3ea2e2c1aa..ffd102c081 100644 --- a/backend/windmill-queue/src/lib.rs +++ b/backend/windmill-queue/src/lib.rs @@ -6,7 +6,7 @@ * LICENSE-AGPL for a copy of the license. */ -mod jobs; +pub mod jobs; #[cfg(feature = "private")] pub mod jobs_ee; pub mod jobs_oss; diff --git a/backend/windmill-worker/src/ai/tools.rs b/backend/windmill-worker/src/ai/tools.rs index 478eca5e54..84304f232c 100644 --- a/backend/windmill-worker/src/ai/tools.rs +++ b/backend/windmill-worker/src/ai/tools.rs @@ -529,6 +529,7 @@ async fn execute_windmill_tool( &mut occupancy_metrics_spawn, &mut killpill_rx_spawn, None, + None, #[cfg(feature = "benchmark")] &mut bench_spawn, ) @@ -656,8 +657,9 @@ async fn handle_tool_execution_success( .. }) = send_result.as_ref() { + let result = result.clone(); ctx.job_completed_tx - .send(send_result.as_ref().unwrap().result.clone(), true) + .send(send_result.unwrap().result, true) .await .map_err(to_anyhow)?; result diff --git a/backend/windmill-worker/src/bun_executor.rs b/backend/windmill-worker/src/bun_executor.rs index b8723ad815..26c59b77ba 100644 --- a/backend/windmill-worker/src/bun_executor.rs +++ b/backend/windmill-worker/src/bun_executor.rs @@ -9,10 +9,8 @@ use serde_json::value::RawValue; use uuid::Uuid; use windmill_parser_ts::remove_pinned_imports; -use windmill_queue::{append_logs, CanceledBy, MiniPulledJob, PrecomputedAgentInfo}; -#[cfg(feature = "enterprise")] -use crate::common::build_envs_map; +use windmill_queue::{append_logs, CanceledBy, MiniPulledJob, PrecomputedAgentInfo}; use crate::{ common::{ @@ -38,12 +36,6 @@ use tokio::{fs::File, process::Command}; use tokio::io::AsyncReadExt; -#[cfg(feature = "enterprise")] -use tokio::sync::mpsc::Receiver; - -#[cfg(feature = "enterprise")] -use windmill_common::variables; - use windmill_common::{ error::{self, Result}, get_latest_hash_for_path, @@ -1567,10 +1559,18 @@ pub async fn get_common_bun_proc_envs(base_internal_url: Option<&str>) -> HashMa return bun_envs; } -#[cfg(feature = "enterprise")] -use crate::{dedicated_worker::handle_dedicated_process, JobCompletedSender}; +#[cfg(feature = "private")] +use crate::{ + common::build_envs_map, dedicated_worker_oss::handle_dedicated_process, JobCompletedSender, +}; +#[cfg(feature = "private")] +use tokio::sync::mpsc::Receiver; +#[cfg(feature = "private")] +use windmill_common::variables; +#[cfg(feature = "private")] +use windmill_queue::DedicatedWorkerJob; -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] pub async fn start_worker( requirements_o: Option, codebase: Option, @@ -1584,8 +1584,9 @@ pub async fn start_worker( script_path: &str, token: &str, job_completed_tx: JobCompletedSender, - jobs_rx: Receiver>, + jobs_rx: Receiver, killpill_rx: tokio::sync::broadcast::Receiver<()>, + client: windmill_common::client::AuthedClient, ) -> Result<()> { let mut logs = "".to_string(); let mut mem_peak: i32 = 0; @@ -1737,6 +1738,12 @@ BigInt.prototype.toJSON = function () {{ console.log('start'); +function getArgs(line) {{ + let {{ {spread} }} = JSON.parse(line) + {dates} + return [ {spread} ]; +}} + for await (const line of Readline.createInterface({{ input: process.stdin }})) {{ {print_lines} @@ -1744,9 +1751,8 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { process.exit(0); }} try {{ - let {{ {spread} }} = JSON.parse(line) - {dates} - let res = await Main.main(...[ {spread} ]); + const args = getArgs(line); + const res = await Main.main(...args); console.log("wm_res[success]:" + JSON.stringify(res ?? null, (key, value) => typeof value === 'undefined' ? null : value)); }} catch (e) {{ console.log("wm_res[error]:" + JSON.stringify({{ message: e.message, name: e.name, stack: e.stack, line: line }})); @@ -1812,6 +1818,7 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { db, &script_path, "nodejs", + client, ) .await } else { @@ -1838,6 +1845,7 @@ for await (const line of Readline.createInterface({{ input: process.stdin }})) { db, script_path, "bun", + client, ) .await } diff --git a/backend/windmill-worker/src/dedicated_worker.rs b/backend/windmill-worker/src/dedicated_worker.rs deleted file mode 100644 index e65655c94d..0000000000 --- a/backend/windmill-worker/src/dedicated_worker.rs +++ /dev/null @@ -1,759 +0,0 @@ -// use tokio::sync::mpsc; - -// pub fn create_dedicated_worker() { -// let (job_completed_tx, mut new_job) = mpsc::channel::(100); -// } - -use async_recursion::async_recursion; -use std::{collections::VecDeque, process::Stdio, sync::Arc}; -use tokio::sync::mpsc::Sender; -use tokio::{ - io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, - process::Command, - task::JoinHandle, -}; -use windmill_common::error::Error; -use windmill_common::flows::FlowValue; -use windmill_common::worker::WORKER_CONFIG; -use windmill_common::KillpillSender; -use windmill_common::{ - cache, error, - flows::{FlowModule, FlowModuleValue}, - scripts::{ScriptHash, ScriptLang}, - variables, - worker::to_raw_value, - DB, -}; -use windmill_queue::append_logs; -use windmill_queue::MiniPulledJob; - -use anyhow::Context; - -use crate::{common::start_child_process, JobCompletedSender, MAX_BUFFERED_DEDICATED_JOBS}; - -use futures::{future, Future}; -use std::{collections::HashMap, task::Poll}; - -use tokio::sync::mpsc::Receiver; - -fn conditional_polling( - fut: impl Future, - predicate: bool, -) -> impl Future { - let mut fut = Box::pin(fut); - future::poll_fn(move |cx| { - if predicate { - fut.as_mut().poll(cx) - } else { - Poll::Pending - } - }) -} - -async fn write_stdin(stdin: &mut tokio::process::ChildStdin, s: &str) -> error::Result<()> { - let _ = &stdin.write_all(format!("{s}\n").as_bytes()).await?; - stdin.flush().await.context("stdin flush")?; - Ok(()) -} - -#[cfg(feature = "enterprise")] -pub async fn handle_dedicated_process( - command_path: &String, - job_dir: &str, - context_envs: HashMap, - envs: HashMap, - reserved_variables: Vec, - common_bun_proc_envs: HashMap, - args: Vec<&str>, - mut killpill_rx: tokio::sync::broadcast::Receiver<()>, - job_completed_tx: JobCompletedSender, - token: &str, - mut jobs_rx: Receiver>, - worker_name: &str, - db: &DB, - script_path: &str, - mode: &str, -) -> std::result::Result<(), error::Error> { - //do not cache local dependencies - - use windmill_queue::{JobCompleted, MiniCompletedJob}; - - use crate::{handle_child::process_status, PROXY_ENVS}; - let cmd_name = format!("dedicated {command_path}"); - let mut child = { - let mut cmd = Command::new(command_path); - cmd.current_dir(job_dir) - .env_clear() - .envs(context_envs) - .envs(envs) - .envs(PROXY_ENVS.clone()) - .envs( - reserved_variables - .iter() - .map(|x| (x.name.clone(), x.value.clone())) - .collect::>(), - ) - .envs(common_bun_proc_envs) - .args(args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - start_child_process(cmd, command_path, false).await? - }; - - let stdout = child - .stdout() - .take() - .expect("child did not have a handle to stdout"); - - let stderr = child - .stderr() - .take() - .expect("child did not have a handle to stderr"); - - let mut reader = BufReader::new(stdout).lines(); - - let mut err_reader = BufReader::new(stderr).lines(); - - let mut stdin = child - .stdin() - .take() - .expect("child did not have a handle to stdin"); - - // Ensure the child process is spawned in the runtime so it can - // make progress on its own while we await for any output. - let child = tokio::spawn(async move { - let status = Box::into_pin(child.wait()) - .await - .expect("child process encountered an error"); - if let Err(e) = process_status(&cmd_name, status, vec![]) { - tracing::error!("child exit status was not success: {e:#}"); - } else { - tracing::info!("child exit status was success"); - } - }); - - let mut jobs: VecDeque = VecDeque::with_capacity(MAX_BUFFERED_DEDICATED_JOBS); - // let mut i = 0; - // let mut j = 0; - let mut alive = true; - - let init_log = format!("dedicated worker {mode}: {worker_name}\n\n"); - let mut logs = init_log.clone(); - loop { - tokio::select! { - biased; - _ = killpill_rx.recv(), if alive => { - println!("received killpill for dedicated worker"); - alive = false; - if let Err(e) = write_stdin(&mut stdin, "end").await { - tracing::info!("Could not write end message to stdin: {e:?}") - } - stdin.flush().await.context("stdin flush")?; - }, - line = err_reader.next_line() => { - if let Some(line) = line.expect("line is ok") { - tracing::error!("stderr dedicated worker: {line}"); - logs.push_str("[stderr] "); - logs.push_str(&line); - logs.push_str("\n"); - } else { - tracing::info!("dedicated worker process exited {script_path}"); - let mut last_stdout = "".to_string(); - while let Some(line) = reader.next_line().await.ok().flatten() { - last_stdout = line; - last_stdout.push_str("\n"); - } - tracing::info!("Last stdout for {script_path}: {last_stdout}"); - break; - } - }, - line = reader.next_line() => { - // j += 1; - - if let Some(line) = line.expect("line is ok") { - if line == "start" { - tracing::info!("dedicated worker process started {script_path}"); - continue; - } - tracing::debug!("processed job: |{line}|"); - if line.starts_with("wm_res[") { - let job = jobs.pop_front().expect("pop"); - tracing::info!("job completed on dedicated worker {script_path}: {}", job.id); - match serde_json::from_str::>(&line.replace("wm_res[success]:", "").replace("wm_res[error]:", "")) { - Ok(result) => { - let result = Arc::new(result); - append_logs(&job.id, &job.workspace_id, logs.clone(), &db.into()).await; - if line.starts_with("wm_res[success]:") { - job_completed_tx.send_job(JobCompleted { job , result, result_columns: None, mem_peak: 0, canceled_by: None, success: true, cached_res_path: None, token: token.to_string(), duration: None, preprocessed_args: None, has_stream: Some(false), from_cache: None }, true).await.unwrap() - } else { - job_completed_tx.send_job(JobCompleted { job , result, result_columns: None, mem_peak: 0, canceled_by: None, success: false, cached_res_path: None, token: token.to_string(), duration: None, preprocessed_args: None, has_stream: Some(false), from_cache: None }, true).await.unwrap() - } - }, - Err(e) => { - tracing::error!("Could not deserialize job result `{line}`: {e:?}"); - job_completed_tx.send_job(JobCompleted { job , result: Arc::new(to_raw_value(&serde_json::json!({"error": format!("Could not deserialize job result `{line}`: {e:?}")}))), result_columns: None, mem_peak: 0, canceled_by: None, success: false, cached_res_path: None, token: token.to_string(), duration: None, preprocessed_args: None, has_stream: Some(false), from_cache: None }, true).await.unwrap(); - }, - }; - logs = init_log.clone(); - } else { - logs.push_str(&line); - logs.push_str("\n"); - } - } else { - tracing::info!("dedicated worker {script_path} process exited"); - let mut last_stderr = "".to_string(); - while let Some(line) = err_reader.next_line().await.ok().flatten() { - last_stderr = line; - last_stderr.push_str("\n"); - } - tracing::info!("Last stderr for {script_path}: {last_stderr}"); - break; - } - }, - job = conditional_polling(jobs_rx.recv(), alive && jobs.len() < MAX_BUFFERED_DEDICATED_JOBS) => { - // i += 1; - if let Some(job) = job { - let id = job.id; - let args = serde_json::to_string(&job.args).expect("serialize"); - jobs.push_back(MiniCompletedJob::from(job)); - tracing::info!("received job and adding to queue on dedicated worker for {script_path}: {} (queue_size: {})", id, jobs.len()); - - // write_stdin(&mut stdin, &serde_json::to_string(&job.args.unwrap_or_else(|| serde_json::json!({"x": job.id}))).expect("serialize")).await?; - write_stdin(&mut stdin, &args).await?; - stdin.flush().await.context("stdin flush")?; - // tracing::info!("wrote job to stdin for {script_path}: {} (queue_size: {})", id, jobs.len()); - } else { - tracing::debug!("job channel closed"); - alive = false; - if let Err(e) = write_stdin(&mut stdin, "end").await { - tracing::error!("Could not write end message to stdin: {e:?}") - } - } - } - } - } - - child - .await - .map_err(|e| anyhow::anyhow!("child process {script_path} encountered an error: {e:#}"))?; - - tracing::info!("dedicated worker {script_path} child process exited successfully"); - Ok(()) -} - -type DedicatedWorker = ( - String, - Sender>, - Option>, -); - -// spawn one dedicated worker per compatible steps of the flow, associating the node id to the dedicated worker channel send -#[async_recursion] -#[cfg(feature = "enterprise")] -async fn spawn_dedicated_workers_for_flow( - modules: &Vec, - w_id: &str, - path: &str, - killpill_tx: KillpillSender, - killpill_rx: &tokio::sync::broadcast::Receiver<()>, - db: &DB, - worker_dir: &str, - base_internal_url: &str, - worker_name: &str, - job_completed_tx: &JobCompletedSender, -) -> Vec { - let mut workers = vec![]; - let mut script_path_to_worker: HashMap>> = - HashMap::new(); - for module in modules.iter() { - let value = module.get_value(); - if let Ok(value) = value { - match &value { - FlowModuleValue::Script { path, hash, .. } => { - let key = format!( - "{}:{}", - path, - hash.clone() - .map(|x| x.to_string()) - .unwrap_or_else(|| "".to_string()) - ); - if let Some(sender) = script_path_to_worker.get(&key) { - workers.push((module.id.clone(), sender.clone(), None)); - } else { - if let Some(dedi_w) = spawn_dedicated_worker( - SpawnWorker::Script { path: path.to_string(), hash: hash.clone() }, - w_id, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - Some(module.id.clone()), - ) - .await - { - script_path_to_worker.insert(key, dedi_w.1.clone()); - workers.push(dedi_w); - } - } - } - FlowModuleValue::ForloopFlow { modules, .. } => { - let w = spawn_dedicated_workers_for_flow( - &modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - FlowModuleValue::WhileloopFlow { modules, .. } => { - let w = spawn_dedicated_workers_for_flow( - &modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - FlowModuleValue::BranchOne { branches, default, .. } => { - for modules in branches - .iter() - .map(|x| &x.modules) - .chain(std::iter::once(default)) - { - let w = spawn_dedicated_workers_for_flow( - &modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - } - FlowModuleValue::BranchAll { branches, .. } => { - for branch in branches { - let w = spawn_dedicated_workers_for_flow( - &branch.modules, - w_id, - path, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - ) - .await; - workers.extend(w); - } - } - FlowModuleValue::RawScript { content, lock, path: spath, language, .. } => { - if let Some(dedi_w) = spawn_dedicated_worker( - SpawnWorker::RawScript { - path: spath.clone().unwrap_or(path.to_string()), - content: content.to_string(), - lock: lock.clone(), - lang: language.clone(), - }, - w_id, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - Some(module.id.clone()), - ) - .await - { - workers.push(dedi_w); - } - } - FlowModuleValue::FlowScript { id, language, .. } => { - let spawn = cache::flow::fetch_script( - &windmill_common::worker::Connection::Sql(db.clone()), - *id, - ) - .await - .map(|data| SpawnWorker::RawScript { - path: "".to_string(), - content: data.code.clone(), - lock: data.lock.clone(), - lang: *language, - }); - match spawn { - Ok(spawn) => { - if let Some(dedi_w) = spawn_dedicated_worker( - spawn, - w_id, - killpill_tx.clone(), - killpill_rx, - db, - worker_dir, - base_internal_url, - worker_name, - job_completed_tx, - Some(module.id.clone()), - ) - .await - { - workers.push(dedi_w); - } - } - Err(err) => tracing::error!( - "failed to get script for module: {:?}, err: {:?}", - module, - err - ), - } - } - FlowModuleValue::Flow { .. } => (), - FlowModuleValue::Identity => (), - FlowModuleValue::AIAgent { .. } => (), - } - } else { - tracing::error!("failed to get value for module: {:?}", module); - } - } - workers -} - -pub async fn create_dedicated_worker_map( - killpill_tx: &KillpillSender, - killpill_rx: &tokio::sync::broadcast::Receiver<()>, - db: &DB, - worker_dir: &str, - base_internal_url: &str, - worker_name: &str, - job_completed_tx: &JobCompletedSender, -) -> ( - HashMap>>, - bool, - Vec>, -) { - let mut dedicated_handles = vec![]; - if let Some(_wp) = WORKER_CONFIG.read().await.dedicated_worker.clone() { - let mut hm = HashMap::new(); - let is_flow_worker; - if let Some(flow_path) = _wp.path.strip_prefix("flow/") { - is_flow_worker = true; - let value = sqlx::query_scalar!( - "SELECT flow_version.value AS \"value!: sqlx::types::Json>\" - FROM flow - LEFT JOIN flow_version - ON flow_version.id = flow.versions[array_upper(flow.versions, 1)] - WHERE flow.path = $1 AND flow.workspace_id = $2", - flow_path, - _wp.workspace_id - ) - .fetch_optional(db) - .await; - if let Ok(v) = value { - if let Some(v) = v { - let value = serde_json::from_str::(v.get()).map_err(|err| { - Error::internal_err(format!( - "could not convert json to flow for {flow_path}: {err:?}" - )) - }); - if let Ok(flow) = value { - let workers = spawn_dedicated_workers_for_flow( - &flow.modules, - &_wp.workspace_id, - &_wp.path, - killpill_tx.clone(), - &killpill_rx, - db, - &worker_dir, - base_internal_url, - &worker_name, - &job_completed_tx, - ) - .await; - workers.into_iter().for_each(|(path, sender, handle)| { - tracing::info!("spawned dedicated worker for flow: {}", path.as_str()); - if let Some(h) = handle { - dedicated_handles.push(h); - } - hm.insert(path, sender); - }); - } - } else { - tracing::error!( - "flow present but value not found for dedicated worker. {}", - flow_path - ); - } - } else { - tracing::error!("flow not found for dedicated worker: {}. Waiting for dependency job and expected to restart.", flow_path); - } - } else { - is_flow_worker = false; - if let Some((path, sender, handle)) = spawn_dedicated_worker( - SpawnWorker::Script { path: _wp.path.clone(), hash: None }, - &_wp.workspace_id, - killpill_tx.clone(), - &killpill_rx, - db, - &worker_dir, - base_internal_url, - &worker_name, - &job_completed_tx, - None, - ) - .await - { - if let Some(h) = handle { - dedicated_handles.push(h); - } - hm.insert(path, sender); - } else { - tracing::error!( - "failed to spawn dedicated worker for {}, script not found", - _wp.path - ); - } - } - (hm, is_flow_worker, dedicated_handles) - } else { - (HashMap::new(), false, dedicated_handles) - } -} - -#[derive(Debug, Clone)] -pub enum SpawnWorker { - Script { path: String, hash: Option }, - RawScript { path: String, content: String, lock: Option, lang: ScriptLang }, -} - -// spawn one dedicated worker and return the key, the channel sender and the join handle -// note that for it will return none for language that do not support dedicated workers -// note that go using cache binary does not need dedicated workers so all languages are supported -#[cfg(feature = "enterprise")] -async fn spawn_dedicated_worker( - sw: SpawnWorker, - w_id: &str, - killpill_tx: KillpillSender, - killpill_rx: &tokio::sync::broadcast::Receiver<()>, - db: &DB, - worker_dir: &str, - base_internal_url: &str, - worker_name: &str, - job_completed_tx: &JobCompletedSender, - node_id: Option, -) -> Option { - use windmill_common::{ - error::Error, - scripts::{ScriptHash, ScriptLang}, - utils::rd_string, - }; - use windmill_queue::MiniPulledJob; - - use crate::{build_envs, get_script_content_by_hash, ContentReqLangEnvs}; - - #[cfg(not(feature = "enterprise"))] - { - tracing::error!("Dedicated worker is an enterprise feature"); - killpill_tx.send(()).expect("send"); - return None; - } - - #[cfg(feature = "enterprise")] - { - let (dedicated_worker_tx, dedicated_worker_rx) = tokio::sync::mpsc::channel::< - std::sync::Arc, - >(MAX_BUFFERED_DEDICATED_JOBS); - let killpill_rx = killpill_rx.resubscribe(); - let db2 = db.clone(); - let base_internal_url = base_internal_url.to_string(); - let worker_name = worker_name.to_string(); - let job_completed_tx = job_completed_tx.clone(); - let job_dir = format!( - "{}/dedicated{}", - worker_dir, - node_id - .as_ref() - .map(|x| format!("-{x}")) - .unwrap_or_else(|| "".to_string()) - ); - tokio::fs::create_dir_all(&job_dir) - .await - .expect("create dir"); - - let path = match &sw { - SpawnWorker::RawScript { path, .. } => path.to_string(), - SpawnWorker::Script { path, .. } => path.to_string(), - }; - - let path2 = path.clone(); - let w_id = w_id.to_string(); - - let (content, lock, language, envs, codebase) = match sw.clone() { - SpawnWorker::Script { path, hash } => { - let q = if let Some(hash) = hash { - get_script_content_by_hash(&hash, &w_id, &db2.into()) - .await - .map(|r: ContentReqLangEnvs| { - Some((r.content, r.lockfile, r.language, r.envs, r.codebase)) - }) - } else { - sqlx::query_as::<_, (String, Option, Option, Option>, bool, Option)>( - "SELECT content, lock, language, envs, codebase IS NOT NULL, hash FROM script WHERE path = $1 AND workspace_id = $2 AND - archived = false AND lock IS not NULL AND lock_error_logs IS NULL ORDER BY created_at DESC LIMIT 1", - ) - .bind(&path) - .bind(&w_id) - .fetch_optional(&db2) - .await - .map_err(|e| Error::internal_err(format!("expected content and lock: {e:#}"))) - .map(|x| x.map(|y| (y.0, y.1, y.2, y.3, if y.4 { y.5.map(|z| z.to_string()) } else { None }))) - }; - if let Ok(q) = q { - if let Some(wp) = q { - wp - } else { - tracing::error!( - "Failed to fetch script `{}` in workspace {} for dedicated worker.", - path, - w_id - ); - return None; - } - } else { - tracing::error!("Failed to fetch script for dedicated worker"); - killpill_tx.send(); - return None; - } - } - SpawnWorker::RawScript { content, lock, lang, .. } => { - (content, lock, Some(lang), None, None) - } - }; - - match language { - Some(ScriptLang::Python3) | Some(ScriptLang::Bun) | Some(ScriptLang::Deno) => {} - _ => return None, - } - - let db = db.clone(); - let handle = tokio::spawn(async move { - let token = { - let token = rd_string(32); - if let Err(e) = sqlx::query_scalar!( - "INSERT INTO token - (token, label, super_admin, email) - VALUES ($1, $2, $3, $4)", - token, - "dedicated_worker", - true, - "dedicated_worker@windmill.dev" - ) - .execute(&db) - .await - { - tracing::error!("failed to create token for dedicated worker: {:?}", e); - killpill_tx.clone().send(); - }; - token - }; - - let worker_envs = build_envs(envs.as_ref()).expect("failed to build envs"); - - if let Err(e) = match language { - Some(ScriptLang::Python3) => { - #[cfg(not(feature = "python"))] - { - tracing::error!("Python requires the python feature to be enabled"); - killpill_tx.send(); - return; - } - - #[cfg(feature = "python")] - crate::python_executor::start_worker( - lock.as_ref(), - &db, - &content, - &base_internal_url, - &job_dir, - &worker_name, - worker_envs, - &w_id, - &path, - &token, - job_completed_tx, - dedicated_worker_rx, - killpill_rx, - ) - .await - } - Some(ScriptLang::Bun) => { - crate::bun_executor::start_worker( - lock, - codebase, - &db, - &content, - &base_internal_url, - &job_dir, - &worker_name, - worker_envs, - &w_id, - &path, - &token, - job_completed_tx, - dedicated_worker_rx, - killpill_rx, - ) - .await - } - Some(ScriptLang::Deno) => { - crate::deno_executor::start_worker( - &content, - &base_internal_url, - &job_dir, - &worker_name, - worker_envs, - &w_id, - &path, - &token, - job_completed_tx, - dedicated_worker_rx, - killpill_rx, - &db, - ) - .await - } - _ => unreachable!("Non supported language for dedicated worker"), - } { - tracing::error!("error in dedicated worker for {sw:#?}: {:?}", e); - }; - killpill_tx.clone().send(); - }); - return Some((node_id.unwrap_or(path2), dedicated_worker_tx, Some(handle))); - // (Some(dedi_path), Some(dedicated_worker_tx), Some(handle)) - } -} diff --git a/backend/windmill-worker/src/dedicated_worker_oss.rs b/backend/windmill-worker/src/dedicated_worker_oss.rs new file mode 100644 index 0000000000..09e86193e0 --- /dev/null +++ b/backend/windmill-worker/src/dedicated_worker_oss.rs @@ -0,0 +1,26 @@ +#[cfg(feature = "private")] +// #[allow(unused)] +pub use crate::dedicated_worker_ee::*; + +#[cfg(not(feature = "private"))] +pub async fn spawn_flow_module_runners( + _job: &windmill_queue::MiniPulledJob, + _module: &windmill_common::flows::FlowModule, + _failure_module: Option<&Box>, + _killpill_rx: &tokio::sync::broadcast::Receiver<()>, + _db: &windmill_common::db::DB, + _worker_dir: &str, + _base_internal_url: &str, + _worker_name: &str, + _job_completed_tx: &crate::JobCompletedSender, +) -> windmill_common::error::Result<( + std::collections::HashMap< + String, + tokio::sync::mpsc::Sender, + >, + Vec>, +)> { + Err(windmill_common::error::Error::internal_err( + "Squashing flow loops is not available in OSS".to_string(), + )) +} diff --git a/backend/windmill-worker/src/deno_executor.rs b/backend/windmill-worker/src/deno_executor.rs index 332cd142db..e80eec265d 100644 --- a/backend/windmill-worker/src/deno_executor.rs +++ b/backend/windmill-worker/src/deno_executor.rs @@ -514,13 +514,14 @@ async fn build_import_map( Ok(()) as error::Result<()> } -#[cfg(feature = "enterprise")] -use crate::{dedicated_worker::handle_dedicated_process, JobCompletedSender}; - -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] +use crate::{dedicated_worker_oss::handle_dedicated_process, JobCompletedSender}; +#[cfg(feature = "private")] use tokio::sync::mpsc::Receiver; +#[cfg(feature = "private")] +use windmill_queue::DedicatedWorkerJob; -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] pub async fn start_worker( inner_content: &str, base_internal_url: &str, @@ -531,9 +532,10 @@ pub async fn start_worker( script_path: &str, token: &str, job_completed_tx: JobCompletedSender, - jobs_rx: Receiver>, + jobs_rx: Receiver, killpill_rx: tokio::sync::broadcast::Receiver<()>, db: &sqlx::Pool, + client: windmill_common::client::AuthedClient, ) -> Result<()> { use windmill_common::variables; @@ -654,6 +656,7 @@ for await (const chunk of Deno.stdin.readable) {{ db, script_path, "deno", + client, ) .await } diff --git a/backend/windmill-worker/src/lib.rs b/backend/windmill-worker/src/lib.rs index 4bf60f6d4a..c5db591c42 100644 --- a/backend/windmill-worker/src/lib.rs +++ b/backend/windmill-worker/src/lib.rs @@ -23,8 +23,10 @@ mod bun_executor; pub mod common; mod config; mod csharp_executor; -#[cfg(feature = "enterprise")] -mod dedicated_worker; + +#[cfg(feature = "private")] +mod dedicated_worker_ee; +mod dedicated_worker_oss; mod deno_executor; #[cfg(feature = "duckdb")] mod duckdb_executor; diff --git a/backend/windmill-worker/src/python_executor.rs b/backend/windmill-worker/src/python_executor.rs index bc84a2e19f..b417014d85 100644 --- a/backend/windmill-worker/src/python_executor.rs +++ b/backend/windmill-worker/src/python_executor.rs @@ -18,6 +18,8 @@ use tokio::{ sync::Semaphore, task, }; +use windmill_queue::MiniPulledJob; + use uuid::Uuid; #[cfg(all(feature = "enterprise", feature = "parquet", unix))] use windmill_common::ee_oss::{get_license_plan, LicensePlan}; @@ -546,7 +548,6 @@ pub async fn handle_python_job( precomputed_agent_info: Option, has_stream: &mut bool, ) -> windmill_common::error::Result> { - let script_path = crate::common::use_flow_root_path(job.runnable_path()); let annotations = PythonAnnotations::parse(inner_content); @@ -2130,16 +2131,16 @@ fn get_result_postprocessor<'a>(skip: bool) -> &'a str { } } -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] use crate::JobCompletedSender; -#[cfg(feature = "enterprise")] -use crate::{common::build_envs_map, dedicated_worker::handle_dedicated_process}; -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] +use crate::{common::build_envs_map, dedicated_worker_oss::handle_dedicated_process}; +#[cfg(feature = "private")] use windmill_common::variables; +#[cfg(feature = "private")] +use windmill_queue::DedicatedWorkerJob; -use windmill_queue::MiniPulledJob; - -#[cfg(feature = "enterprise")] +#[cfg(feature = "private")] pub async fn start_worker( requirements_o: Option<&String>, db: &sqlx::Pool, @@ -2152,10 +2153,12 @@ pub async fn start_worker( script_path: &str, token: &str, job_completed_tx: JobCompletedSender, - jobs_rx: tokio::sync::mpsc::Receiver>, + jobs_rx: tokio::sync::mpsc::Receiver, killpill_rx: tokio::sync::broadcast::Receiver<()>, + client: windmill_common::client::AuthedClient, ) -> error::Result<()> { use crate::{PyV, PyVAlias}; + tracing::info!("script path: {}", script_path); let mut mem_peak: i32 = 0; let mut canceled_by: Option = None; @@ -2346,6 +2349,7 @@ for line in sys.stdin: db, script_path, "python", + client, ) .await } diff --git a/backend/windmill-worker/src/result_processor.rs b/backend/windmill-worker/src/result_processor.rs index 1e168d3a30..e5a7a0052c 100644 --- a/backend/windmill-worker/src/result_processor.rs +++ b/backend/windmill-worker/src/result_processor.rs @@ -31,8 +31,8 @@ use windmill_common::{ use windmill_common::bench::{BenchmarkInfo, BenchmarkIter}; use windmill_queue::{ - append_logs, get_mini_completed_job, CanceledBy, JobCompleted, MiniCompletedJob, MiniPulledJob, - ValidableJson, WrappedError, INIT_SCRIPT_TAG, + append_logs, get_mini_completed_job, CanceledBy, FlowRunners, JobCompleted, MiniCompletedJob, + MiniPulledJob, ValidableJson, WrappedError, INIT_SCRIPT_TAG, }; use serde_json::{json, value::RawValue, Value}; @@ -66,6 +66,7 @@ async fn process_jc( same_worker_tx: Option<&SameWorkerSender>, job_completed_sender: &JobCompletedSender, stats_map: &JobStatsMap, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { let success: bool = jc.success; @@ -155,6 +156,7 @@ async fn process_jc( same_worker_tx, &worker_name, job_completed_sender.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -285,6 +287,7 @@ pub fn start_background_processor( Some(&same_worker_tx), &job_completed_sender, &stats_map, + &killpill_rx, #[cfg(feature = "benchmark")] &mut bench, ) @@ -350,6 +353,8 @@ pub fn start_background_processor( stop_early_override, &worker_name, job_completed_sender.clone(), + None, + &killpill_rx, #[cfg(feature = "benchmark")] &mut bench, ) @@ -413,6 +418,7 @@ pub async fn process_result( conn: &Connection, duration: Option, has_stream: bool, + flow_runners: Option>, ) -> error::Result { match result { Ok(result) => { @@ -431,6 +437,8 @@ pub async fn process_result( duration, has_stream: Some(has_stream), from_cache: None, + flow_runners, + done_tx: None, }, ) .with_context(windmill_common::otel_oss::otel_ctx()) @@ -495,6 +503,8 @@ pub async fn process_result( duration, has_stream: Some(has_stream), from_cache: None, + flow_runners, + done_tx: None, }, ) .with_context(windmill_common::otel_oss::otel_ctx()) @@ -512,6 +522,7 @@ pub async fn handle_receive_completed_job( same_worker_tx: Option<&SameWorkerSender>, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> Option> { let token = jc.token.clone(); @@ -529,6 +540,7 @@ pub async fn handle_receive_completed_job( same_worker_tx.clone(), worker_name, job_completed_tx.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -548,6 +560,7 @@ pub async fn handle_receive_completed_job( &worker_dir, worker_name, job_completed_tx, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -571,6 +584,8 @@ pub async fn process_completed_job( preprocessed_args, has_stream, from_cache, + flow_runners, + done_tx, .. }: JobCompleted, client: &AuthedClient, @@ -579,6 +594,7 @@ pub async fn process_completed_job( same_worker_tx: Option<&SameWorkerSender>, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result>> { if success { @@ -661,12 +677,19 @@ pub async fn process_completed_job( None, worker_name, job_completed_tx, + flow_runners, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) .warn_after_seconds(10) .await?; add_time!(bench, "updated flow status END"); + if let Some(done_tx) = done_tx { + done_tx + .send(()) + .expect("done receiver should still be alive"); + } return Ok(r); } } @@ -707,11 +730,18 @@ pub async fn process_completed_job( None, worker_name, job_completed_tx, + flow_runners, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) .warn_after_seconds(10) .await?; + if let Some(done_tx) = done_tx { + done_tx + .send(()) + .expect("done receiver should still be alive"); + } return Ok(r); } } @@ -761,6 +791,7 @@ pub async fn handle_job_error( worker_dir: &str, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { let err_string = format!("{}: {}", err.name(), err.to_string()); @@ -809,6 +840,8 @@ pub async fn handle_job_error( None, worker_name, job_completed_tx.clone(), + None, + killpill_rx, #[cfg(feature = "benchmark")] bench, ) diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index 9b47aa5113..2919243dbc 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -11,6 +11,7 @@ use anyhow::anyhow; use futures::TryFutureExt; +use tokio::sync::Mutex; use tokio::time::sleep; use tokio::time::timeout; use windmill_common::client::AuthedClient; @@ -59,6 +60,8 @@ use std::{ time::Duration, }; use windmill_parser::MainArgSignature; +use windmill_queue::DedicatedWorkerJob; +use windmill_queue::FlowRunners; use windmill_queue::MiniCompletedJob; use windmill_queue::PulledJobResultToJobErr; @@ -167,8 +170,8 @@ use crate::duckdb_executor::do_duckdb; #[cfg(all(feature = "enterprise", feature = "oracledb"))] use crate::oracledb_executor::do_oracledb; -#[cfg(feature = "enterprise")] -use crate::dedicated_worker::create_dedicated_worker_map; +#[cfg(all(feature = "private", feature = "enterprise"))] +use crate::dedicated_worker_oss::create_dedicated_worker_map; #[cfg(feature = "enterprise")] use crate::snowflake_executor::do_snowflake; @@ -532,6 +535,8 @@ lazy_static::lazy_static! { .ok() .and_then(|x| x.parse::().ok()) .unwrap_or(1000); + + pub static ref FLOW_RUNNER_RUNNING: Mutex = Mutex::new(false); } type Envs = Vec<(String, String)>; @@ -558,14 +563,14 @@ lazy_static::lazy_static! { #[derive(Debug)] pub enum NextJob { - Sql(PulledJob), + Sql { job: PulledJob, flow_runners: Option> }, Http(JobAndPerms), } impl NextJob { pub fn job(self) -> MiniPulledJob { match self { - NextJob::Sql(job) => job.job, + NextJob::Sql { job, .. } => job.job, NextJob::Http(job) => job.job, } } @@ -575,7 +580,7 @@ impl std::ops::Deref for NextJob { type Target = MiniPulledJob; fn deref(&self) -> &Self::Target { match self { - NextJob::Sql(job) => &job.job, + NextJob::Sql { job, .. } => &job.job, NextJob::Http(job) => &job.job, } } @@ -733,10 +738,10 @@ impl JobCompletedSender { impl SameWorkerSender { pub async fn send( &self, - payload: SameWorkerPayload, + message: SameWorkerPayload, ) -> Result<(), tokio::sync::mpsc::error::SendError> { self.1.fetch_add(1, Ordering::Relaxed); - self.0.send(payload).await + self.0.send(message).await } } @@ -829,18 +834,36 @@ fn add_outstanding_wait_time( async fn extract_job_and_perms(job: NextJob, conn: &Connection) -> JobAndPerms { match (job, conn) { - (NextJob::Sql(job), Connection::Sql(db)) => job.get_job_and_perms(db).await, - (NextJob::Sql(_), Connection::Http(_)) => panic!("sql job on http connection"), + (NextJob::Sql { job, flow_runners, .. }, Connection::Sql(db)) => { + JobAndPerms { flow_runners, ..job.get_job_and_perms(db).await } + } + (NextJob::Sql { .. }, Connection::Http(_)) => panic!("sql job on http connection"), (NextJob::Http(job), _) => job, } } -fn create_span(arc_job: &Arc, worker_name: &str, hostname: &str) -> Span { - let span = tracing::span!(tracing::Level::INFO, "job", - job_id = %arc_job.id, root_job = field::Empty, workspace_id = %arc_job.workspace_id, worker = %worker_name, hostname = %hostname, tag = %arc_job.tag, +pub fn create_span_with_name( + arc_job: &MiniPulledJob, + worker_name: &str, + hostname: Option<&str>, + span_name: &str, +) -> Span { + // The span macro requires a literal, so we use a fixed name and set otel.name dynamically + let span = tracing::span!( + tracing::Level::INFO, + "job", + job_id = %arc_job.id, + root_job = field::Empty, + workspace_id = %arc_job.workspace_id, + worker = %worker_name, + hostname = field::Empty, + tag = %arc_job.tag, language = field::Empty, - script_path = field::Empty, flow_step_id = field::Empty, parent_job = field::Empty, - otel.name = field::Empty); + script_path = field::Empty, + flow_step_id = field::Empty, + parent_job = field::Empty, + otel.name = field::Empty + ); let rj = arc_job.flow_innermost_root_job.unwrap_or(arc_job.id); @@ -848,10 +871,10 @@ fn create_span(arc_job: &Arc, worker_name: &str, hostname: &str) span.record("language", lg.as_str()); } if let Some(step_id) = arc_job.flow_step_id.as_ref() { - span.record("otel.name", format!("job {}", step_id).as_str()); + span.record("otel.name", format!("{} {}", span_name, step_id).as_str()); span.record("flow_step_id", step_id.as_str()); } else { - span.record("otel.name", "job"); + span.record("otel.name", span_name); } if let Some(parent_job) = arc_job.parent_job.as_ref() { span.record("parent_job", parent_job.to_string().as_str()); @@ -862,6 +885,9 @@ fn create_span(arc_job: &Arc, worker_name: &str, hostname: &str) if let Some(root_job) = arc_job.flow_innermost_root_job.as_ref() { span.record("root_job", root_job.to_string().as_str()); } + if let Some(hostname) = hostname { + span.record("hostname", hostname); + } windmill_common::otel_oss::set_span_parent(&span, &rj); span @@ -876,6 +902,7 @@ pub async fn handle_all_job_kind_error( worker_dir: &str, worker_name: &str, job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) { match conn { @@ -892,6 +919,7 @@ pub async fn handle_all_job_kind_error( &worker_dir, &worker_name, job_completed_tx.clone(), + &killpill_rx, #[cfg(feature = "benchmark")] bench, ) @@ -915,6 +943,8 @@ pub async fn handle_all_job_kind_error( duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }, false, ) @@ -962,27 +992,21 @@ pub fn start_interactive_worker_shell( .await; match job { - Ok(j) => match j.to_pulled_job() { - Ok(j) => Ok(j.clone().map(NextJob::Sql)), - ref e @ (Err(PulledJobResultToJobErr::MissingConcurrencyKey( - ref jc, - )) - | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing( - ref jc, - ))) => { - if let Err(err) = - job_completed_tx.send_job(jc.clone(), true).await - { - let e_fmt = match e { - Ok(_) => "unknown error".to_owned(), - Err(e) => e.to_string(), - }; - - tracing::error!("An error occurred while sending job completed ({e_fmt}): {:#?}", err) + Ok(j) => { + match j.to_pulled_job() { + Ok(j) => Ok(j + .clone() + .map(|job| NextJob::Sql { flow_runners: None, job })), + Err(PulledJobResultToJobErr::MissingConcurrencyKey(jc)) + | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing(jc)) => { + if let Err(err) = job_completed_tx.send_job(jc, true).await + { + tracing::error!("An error occurred while sending job completed: {:#?}", err) + } + Ok(None) } - Ok(None) } - }, + } Err(err) => Err(err), } } @@ -1010,6 +1034,7 @@ pub fn start_interactive_worker_shell( parent_runnable_path, token, precomputed_agent_info: precomputed_bundle, + flow_runners, } = extract_job_and_perms(job, &conn).await; let authed_client = AuthedClient::new( @@ -1039,6 +1064,7 @@ pub fn start_interactive_worker_shell( &mut occupancy_metrics, &mut killpill_rx, precomputed_bundle, + flow_runners, #[cfg(feature = "benchmark")] &mut bench, ) @@ -1476,9 +1502,9 @@ pub async fn run_worker( // Option>>, // Option>, - #[cfg(feature = "enterprise")] + #[cfg(all(feature = "private", feature = "enterprise"))] let (dedicated_workers, is_flow_worker, dedicated_handles): ( - HashMap>>, + HashMap>, bool, Vec>, ) = match conn { @@ -1497,9 +1523,9 @@ pub async fn run_worker( Connection::Http(_) => (HashMap::new(), false, vec![]), }; - #[cfg(not(feature = "enterprise"))] + #[cfg(any(not(feature = "private"), not(feature = "enterprise")))] let (dedicated_workers, is_flow_worker, dedicated_handles): ( - HashMap>>, + HashMap>, bool, Vec>, ) = (HashMap::new(), false, vec![]); @@ -1656,7 +1682,7 @@ pub async fn run_worker( if let Ok(same_worker_job) = same_worker_rx.try_recv() { same_worker_queue_size.fetch_sub(1, Ordering::SeqCst); - tracing::debug!( + tracing::info!( worker = %worker_name, hostname = %hostname, "received {} from same worker channel", same_worker_job.job_id @@ -1676,7 +1702,12 @@ pub async fn run_worker( .expect("send kill to job completed tx"); break; } else { - job.map(|x| x.map(NextJob::Sql)) + job.map(|x| { + x.map(|job| NextJob::Sql { + flow_runners: same_worker_job.flow_runners, + job, + }) + }) } } Connection::Http(client) => client @@ -1827,22 +1858,14 @@ pub async fn run_worker( } match job { Ok(pulled_job_result) => match pulled_job_result.to_pulled_job() { - Ok(j) => Ok(j.map(NextJob::Sql)), - ref e @ (Err(PulledJobResultToJobErr::MissingConcurrencyKey( - ref jc, - )) - | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing( - ref jc, - ))) => { - if let Err(err) = - job_completed_tx.send_job(jc.clone(), true).await - { - let e_fmt = match e { - Ok(_) => "unknown error".to_owned(), - Err(e) => e.to_string(), - }; - - tracing::error!("An error occurred while sending job completed ({e_fmt}): {:#?}", err) + Ok(j) => Ok(j.map(|job| NextJob::Sql { flow_runners: None, job })), + Err(PulledJobResultToJobErr::MissingConcurrencyKey(jc)) + | Err(PulledJobResultToJobErr::ErrorWhilePreprocessing(jc)) => { + if let Err(err) = job_completed_tx.send_job(jc, true).await { + tracing::error!( + "An error occurred while sending job completed: {:#?}", + err + ) } Ok(None) } @@ -1874,7 +1897,10 @@ pub async fn run_worker( tracing::debug!(worker = %worker_name, hostname = %hostname, "started handling of job {}", job.id); - if matches!(job.kind, JobKind::Script | JobKind::Preview) { + if matches!( + job.kind, + JobKind::Script | JobKind::Preview | JobKind::FlowScript + ) { if !dedicated_workers.is_empty() { let key_o = if is_flow_worker { job.flow_step_id.as_ref().map(|x| x.to_string()) @@ -1883,8 +1909,12 @@ pub async fn run_worker( }; if let Some(key) = key_o { if let Some(dedicated_worker_tx) = dedicated_workers.get(&key) { - if let Err(e) = dedicated_worker_tx.send(Arc::new(job.job())).await - { + let dedicated_job = DedicatedWorkerJob { + job: Arc::new(job.job()), + flow_runners: None, + done_tx: None, + }; + if let Err(e) = dedicated_worker_tx.send(dedicated_job).await { tracing::info!("failed to send jobs to dedicated workers. Likely dedicated worker has been shut down. This is normal: {e:?}"); } @@ -1898,6 +1928,77 @@ pub async fn run_worker( } } } + + // Extract flow_runners early to use in both dedicated workers and flow runners + let flow_runners = match &job { + NextJob::Sql { flow_runners, .. } => flow_runners.clone(), + NextJob::Http(_) => None, + }; + + if let Some(flow_runners) = flow_runners { + let key_o = job.flow_step_id.as_ref().map(|x| x.to_string()); + if let Some(key) = key_o { + if let Some(flow_runner_tx) = flow_runners.runners.get(&key) { + tracing::info!( + "sending job {} to flow runner step {}", + job.id, + key + ); + let (done_tx, done_rx) = tokio::sync::oneshot::channel::<()>(); + let flow_runners = flow_runners.clone(); + + let job = job.job(); + + let dedicated_job = DedicatedWorkerJob { + job: Arc::new(job.clone()), + flow_runners: Some(flow_runners), + done_tx: Some(done_tx), + }; + + if let Err(e) = flow_runner_tx.send(dedicated_job).await { + let token = match &conn { + Connection::Sql(db) => { + windmill_queue::jobs::create_token(db, &job, None).await + } + _ => "".to_string(), + }; + handle_all_job_kind_error( + &conn, + &AuthedClient::new( + base_internal_url.to_owned(), + job.workspace_id.clone(), + token, + None, + ), + MiniCompletedJob::from(job), + error::Error::InternalErr(format!( + "failed to send jobs to flow runners: {e:?}" + )), + Some(&same_worker_tx), + &worker_dir, + &worker_name, + job_completed_tx.clone(), + &killpill_rx, + #[cfg(feature = "benchmark")] + &mut bench, + ) + .await; + } else { + if let Err(err) = done_rx.await { + tracing::error!("Flow runner done channel has been dropped without being received: {err:?}"); + } + } + + #[cfg(feature = "benchmark")] + { + add_time!(bench, "sent to flow runner"); + infos.add_iter(bench, true); + } + + continue; + } + } + } } if matches!(job.kind, JobKind::Noop) { @@ -1917,6 +2018,8 @@ pub async fn run_worker( duration: None, has_stream: Some(false), from_cache: None, + flow_runners: None, + done_tx: None, }, true, ) @@ -2048,6 +2151,7 @@ pub async fn run_worker( parent_runnable_path, token, precomputed_agent_info: precomputed_bundle, + flow_runners, } = extract_job_and_perms(job, &conn).await; let authed_client = AuthedClient::new( @@ -2059,7 +2163,7 @@ pub async fn run_worker( let arc_job = Arc::new(job); - let span = create_span(&arc_job, &worker_name, hostname); + let span = create_span_with_name(&arc_job, &worker_name, Some(hostname), "job"); let job_result = handle_queued_job( arc_job.clone(), @@ -2079,6 +2183,7 @@ pub async fn run_worker( &mut occupancy_metrics, &mut killpill_rx2, precomputed_bundle, + flow_runners, #[cfg(feature = "benchmark")] &mut bench, ) @@ -2138,6 +2243,7 @@ pub async fn run_worker( &worker_dir, &worker_name, job_completed_tx.clone(), + &killpill_rx, #[cfg(feature = "benchmark")] &mut bench, ) @@ -2302,7 +2408,7 @@ async fn queue_init_bash_maybe<'c>( }; if let Some((uuid, content)) = uuid_content { same_worker_tx - .send(SameWorkerPayload { job_id: uuid, recoverable: false }) + .send(SameWorkerPayload { job_id: uuid, recoverable: false, flow_runners: None }) .await .map_err(to_anyhow)?; tracing::info!("Creating initial job {uuid} from initial script script: {content}"); @@ -2420,7 +2526,7 @@ async fn queue_periodic_script_bash_maybe<'c>( }; same_worker_tx - .send(SameWorkerPayload { job_id: uuid, recoverable: false }) + .send(SameWorkerPayload { job_id: uuid, recoverable: false, flow_runners: None }) .await .map_err(to_anyhow)?; tracing::info!("Creating periodic script job {uuid} from periodic script: {content}"); @@ -2432,7 +2538,6 @@ pub struct SendResult { pub time: Instant, } -#[derive(Clone)] pub enum SendResultPayload { JobCompleted(JobCompleted), UpdateFlow(UpdateFlow), @@ -2519,6 +2624,7 @@ pub async fn handle_queued_job( occupancy_metrics: &mut OccupancyMetrics, killpill_rx: &mut tokio::sync::broadcast::Receiver<()>, precomputed_agent_info: Option, + flow_runners: Option>, #[cfg(feature = "benchmark")] _bench: &mut BenchmarkIter, ) -> windmill_common::error::Result { // Extract the active span from the context @@ -2646,6 +2752,8 @@ pub async fn handle_queued_job( duration: None, has_stream: Some(false), from_cache: Some(true), + flow_runners: None, + done_tx: None, }, true, ) @@ -2681,6 +2789,8 @@ pub async fn handle_queued_job( worker_dir, job_completed_tx.clone(), worker_name, + flow_runners, + &killpill_rx, )) .warn_after_seconds(10) .await?; @@ -2911,6 +3021,7 @@ pub async fn handle_queued_job( conn, Some(started.elapsed().as_millis() as i64), has_stream, + flow_runners, ) .await } diff --git a/backend/windmill-worker/src/worker_flow.rs b/backend/windmill-worker/src/worker_flow.rs index f0bc4cfc1e..dd45d3b786 100644 --- a/backend/windmill-worker/src/worker_flow.rs +++ b/backend/windmill-worker/src/worker_flow.rs @@ -64,7 +64,7 @@ use windmill_common::{ use windmill_queue::schedule::get_schedule_opt; use windmill_queue::{ add_completed_job, add_completed_job_error, append_logs, get_mini_pulled_job, - handle_maybe_scheduled_job, insert_concurrency_key, interpolate_args, CanceledBy, + handle_maybe_scheduled_job, insert_concurrency_key, interpolate_args, CanceledBy, FlowRunners, MiniCompletedJob, MiniPulledJob, PushArgs, PushIsolationLevel, SameWorkerPayload, WrappedError, }; @@ -88,6 +88,8 @@ pub async fn update_flow_status_after_job_completion( stop_early_override: Option, worker_name: &str, job_completed_tx: JobCompletedSender, + flow_runners: Option>, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result>> { // this is manual tailrecursion because async_recursion blows up the stack @@ -121,6 +123,8 @@ pub async fn update_flow_status_after_job_completion( rec.has_triggered_error_handler, worker_name, job_completed_tx.clone(), + flow_runners.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, )) @@ -147,6 +151,8 @@ pub async fn update_flow_status_after_job_completion( rec.has_triggered_error_handler, worker_name, job_completed_tx.clone(), + flow_runners.clone(), + killpill_rx, #[cfg(feature = "benchmark")] bench, )) @@ -285,6 +291,8 @@ pub async fn update_flow_status_after_job_completion_internal( has_triggered_error_handler: bool, worker_name: &str, job_completed_tx: JobCompletedSender, + flow_runners: Option>, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, #[cfg(feature = "benchmark")] bench: &mut BenchmarkIter, ) -> error::Result { let mut has_triggered_error_handler = has_triggered_error_handler; @@ -434,7 +442,6 @@ pub async fn update_flow_status_after_job_completion_internal( args })); - let from_result_to_args = |args: &Result>, sqlx::Error>| { let args = args .as_ref() @@ -473,7 +480,7 @@ pub async fn update_flow_status_after_job_completion_internal( _ => None, }; let args = from_result_to_args(args.as_ref().await.get_ref())?; - + compute_bool_from_expr( &expr, Marc::new(args), @@ -742,7 +749,6 @@ pub async fn update_flow_status_after_job_completion_internal( &mut stop_early_err_msg, &mut nresult, args, - ) .await?; } @@ -1565,6 +1571,8 @@ pub async fn update_flow_status_after_job_completion_internal( worker_dir, job_completed_tx, worker_name, + flow_runners, + &killpill_rx, )) .warn_after_seconds(10) .await @@ -2044,6 +2052,8 @@ pub async fn handle_flow( worker_dir: &str, job_completed_tx: JobCompletedSender, worker_name: &str, + flow_runners: Option>, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, ) -> anyhow::Result<()> { let flow = flow_data.value(); let status = flow_job @@ -2101,6 +2111,9 @@ pub async fn handle_flow( same_worker_tx, worker_dir, worker_name, + flow_runners.clone(), + job_completed_tx.clone(), + &killpill_rx, )) .warn_after_seconds(10) .await?; @@ -2185,6 +2198,7 @@ struct PushNextFlowJobRec { flow_job: Arc, status: FlowStatus, } + // #[async_recursion] // #[instrument(level = "trace", skip_all)] async fn push_next_flow_job( @@ -2197,6 +2211,9 @@ async fn push_next_flow_job( same_worker_tx: &SameWorkerSender, worker_dir: &str, worker_name: &str, + flow_runners: Option>, + job_completed_tx: JobCompletedSender, + killpill_rx: &tokio::sync::broadcast::Receiver<()>, ) -> error::Result { let job_root = flow_job .flow_innermost_root_job @@ -3028,6 +3045,22 @@ async fn push_next_flow_job( } }; + // only start runners if we're not already in a squash for loop + let start_runners = flow_runners.is_none() + && matches!( + next_status, + NextStatus::NextLoopIteration { start_runners: true, .. } + ); + + let do_not_pass_runners = matches!(next_status, NextStatus::NextStep { .. }) + && flow_runners + .as_ref() + .is_some_and(|fr| fr.job_id == flow_job.id); + + let continue_with_runners = (start_runners || (flow_runners.is_some() && !do_not_pass_runners)) + && module.suspend.is_none() + && module.sleep.is_none(); + // Also check `flow_job.same_worker` for [`JobKind::Flow`] jobs as it's no // more reflected to the flow value on push. let job_same_worker = flow_job.same_worker @@ -3083,6 +3116,7 @@ async fn push_next_flow_job( NextStatus::NextLoopIteration { next: ForloopNextIteration { new_args, .. }, simple_input_transforms, + .. } => { let mut args = if let Ok(args) = nargs { args.as_ref().clone() @@ -3300,7 +3334,7 @@ async fn push_next_flow_job( Some(module.id.clone()), new_job_priority_override, job_perms.as_ref(), - false, + continue_with_runners, None, None, None, @@ -3308,7 +3342,7 @@ async fn push_next_flow_job( .warn_after_seconds(2) .await?; - if continue_on_same_worker { + if continue_on_same_worker || continue_with_runners { let _ = sqlx::query!( "UPDATE v2_job_queue SET worker = $2 WHERE id = $1", uuid, @@ -3583,7 +3617,7 @@ async fn push_next_flow_job( .warn_after_seconds(3) .await?; - if continue_on_same_worker { + if continue_on_same_worker || continue_with_runners { if !is_one_uuid { return Err(Error::BadRequest( "Cannot continue on same worker with multiple jobs, parallel cannot be used in conjunction with same_worker".to_string(), @@ -3593,9 +3627,43 @@ async fn push_next_flow_job( tx.commit().warn_after_seconds(3).await?; tracing::info!(id = %flow_job.id, root_id = %job_root, "all next flow jobs pushed: {uuids:?}"); - if continue_on_same_worker { + if continue_on_same_worker || continue_with_runners { + let flow_runners = if start_runners { + tracing::info!(id = %flow_job.id, "starting flow runners for module {}", module.id); + let (new_flow_runners, new_flow_runner_handles) = + crate::dedicated_worker_oss::spawn_flow_module_runners( + &flow_job, + module, + flow.failure_module.as_ref(), + &killpill_rx, + db, + worker_dir, + &client.base_internal_url, + worker_name, + &job_completed_tx, + ) + .await + .with_context(|| { + format!( + "failed to spawn flow module runners for job: {}", + flow_job.id + ) + })?; + + let flow_runners = FlowRunners { + runners: new_flow_runners, + handles: new_flow_runner_handles, + job_id: flow_job.id, + }; + Some(Arc::new(flow_runners)) + } else if !do_not_pass_runners { + flow_runners + } else { + None + }; + same_worker_tx - .send(SameWorkerPayload { job_id: first_uuid, recoverable: true }) + .send(SameWorkerPayload { job_id: first_uuid, recoverable: true, flow_runners }) .warn_after_seconds(3) .await .map_err(to_anyhow)?; @@ -3702,6 +3770,7 @@ enum NextStatus { NextLoopIteration { next: ForloopNextIteration, simple_input_transforms: Option>, + start_runners: bool, }, AllFlowJobs { branchall: Option, @@ -3943,7 +4012,7 @@ async fn compute_next_flow_transform( NextStatus::NextStep, )) } - FlowModuleValue::WhileloopFlow { modules, modules_node, .. } => { + FlowModuleValue::WhileloopFlow { modules, modules_node, squash, .. } => { // if it's a simple single step flow, we will collapse it as an optimization and need to pass flow_input as an arg let is_simple = is_simple_modules(&modules, flow.failure_module.as_ref()); let (flow_jobs, flow_jobs_success, flow_jobs_duration) = match status_module { @@ -3960,6 +4029,8 @@ async fn compute_next_flow_transform( _ => (vec![], Some(vec![]), Some(FlowJobsDuration::new(0))), }; let next_loop_idx = flow_jobs.len(); + + let start_runners = next_loop_idx == 0 && squash.unwrap_or(false); next_loop_iteration( flow, status, @@ -3982,11 +4053,14 @@ async fn compute_next_flow_transform( db, module, delete_after_use, + start_runners, ) .await } /* forloop modules are expected set `iter: { value: Value, index: usize }` as job arguments */ - FlowModuleValue::ForloopFlow { modules, modules_node, iterator, parallel, .. } => { + FlowModuleValue::ForloopFlow { + modules, modules_node, iterator, parallel, squash, .. + } => { // if it's a simple single step flow, we will collapse it as an optimization and need to pass flow_input as an arg let is_simple = !matches!(flow_job.kind, JobKind::FlowPreview) && !parallel @@ -4025,6 +4099,7 @@ async fn compute_next_flow_transform( Ok(NextFlowTransform::EmptyInnerFlows { branch_chosen: None }) } ForLoopStatus::NextIteration(ns) => { + let start_runners = ns.index == 0 && squash.unwrap_or(false); next_loop_iteration( flow, status, @@ -4036,6 +4111,7 @@ async fn compute_next_flow_transform( db, module, delete_after_use, + start_runners, ) .await } @@ -4300,6 +4376,7 @@ async fn next_loop_iteration( db: &sqlx::Pool, module: &FlowModule, delete_after_use: bool, + start_runners: bool, ) -> Result { let inner_path = || format!("{}/loop-{}", flow_job.runnable_path(), ns.index); if is_simple { @@ -4317,7 +4394,7 @@ async fn next_loop_iteration( ContinuePayload::SingleJob( payload_from_simple_module(value, db, flow_job, module, inner_path()).await?, ), - NextStatus::NextLoopIteration { next: ns, simple_input_transforms }, + NextStatus::NextLoopIteration { next: ns, simple_input_transforms, start_runners }, )); } @@ -4341,7 +4418,7 @@ async fn next_loop_iteration( timeout: None, on_behalf_of: None, }), - NextStatus::NextLoopIteration { next: ns, simple_input_transforms: None }, + NextStatus::NextLoopIteration { next: ns, simple_input_transforms: None, start_runners }, )) } diff --git a/backend/windmill-worker/src/worker_lockfiles.rs b/backend/windmill-worker/src/worker_lockfiles.rs index 824a45c661..4ec0fa648e 100644 --- a/backend/windmill-worker/src/worker_lockfiles.rs +++ b/backend/windmill-worker/src/worker_lockfiles.rs @@ -1193,6 +1193,7 @@ async fn lock_modules<'c>( skip_failures, parallel, parallelism, + squash, } => { let nmodules; (nmodules, tx, nmodified_ids, nerrors) = Box::pin(lock_modules( @@ -1222,6 +1223,7 @@ async fn lock_modules<'c>( skip_failures, parallel, parallelism, + squash, } .into() } @@ -1258,7 +1260,7 @@ async fn lock_modules<'c>( } e.value = FlowModuleValue::BranchAll { branches: nbranches, parallel }.into() } - FlowModuleValue::WhileloopFlow { modules, modules_node, skip_failures } => { + FlowModuleValue::WhileloopFlow { modules, modules_node, skip_failures, squash } => { let nmodules; (nmodules, tx, nmodified_ids, nerrors) = Box::pin(lock_modules( modules, @@ -1284,6 +1286,7 @@ async fn lock_modules<'c>( modules: nmodules, modules_node, skip_failures, + squash, } .into() } diff --git a/frontend/src/lib/components/FlowGraphViewerStep.svelte b/frontend/src/lib/components/FlowGraphViewerStep.svelte index 6fcb5c902c..07ad7756c0 100644 --- a/frontend/src/lib/components/FlowGraphViewerStep.svelte +++ b/frontend/src/lib/components/FlowGraphViewerStep.svelte @@ -121,6 +121,7 @@ {:else if stepDetail.value.type == 'forloopflow'} For loop {#if stepDetail.value.parallel}(parallel){/if} {#if stepDetail.value.skip_failures}(skip failures){/if} + {#if stepDetail.value.squash}(squash){/if} {:else if stepDetail.value.type == 'branchall'} Run all branches {#if stepDetail.value.parallel}(parallel){/if} {:else if stepDetail.value.type == 'branchone'} @@ -128,7 +129,8 @@ {:else if stepDetail.value.type == 'flow'} Inner flow {:else if stepDetail.value.type == 'whileloopflow'} - While loop + While loop {#if stepDetail.value.skip_failures}(skip failures){/if} + {#if stepDetail.value.squash}(squash){/if} {:else if stepDetail.id === 'failure'} Error handler {:else if stepDetail.id === 'preprocessor'} diff --git a/frontend/src/lib/components/flows/content/FlowLoop.svelte b/frontend/src/lib/components/flows/content/FlowLoop.svelte index 50e7bd2a82..4169f49f34 100644 --- a/frontend/src/lib/components/flows/content/FlowLoop.svelte +++ b/frontend/src/lib/components/flows/content/FlowLoop.svelte @@ -32,6 +32,7 @@ import { slide } from 'svelte/transition' import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte' + import Badge from '$lib/components/common/badge/Badge.svelte' const { previewArgs, flowStateStore, flowStore, currentEditor } = getContext('FlowEditorContext') @@ -186,6 +187,33 @@ class="whitespace-nowrap" />
+
+
Squash + + Beta + This can result in unexpected behavior, use at your own risk for now.
+ Squashing a for loop runs all iterations on the same worker, using a single runner + per step for the entire loop. This eliminates cold starts between iterations for supported + languages (Bun, Deno, and Python). +
+
+
+ { + ;(mod.value as ForloopFlow).squash = detail + }} + options={{ + right: 'Squash' + }} + class="whitespace-nowrap" + disabled={mod.value.parallel} + /> +
Run in parallel
diff --git a/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte b/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte index 81bf6c4c11..6983f7c1c6 100644 --- a/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte +++ b/frontend/src/lib/components/flows/content/FlowWhileLoop.svelte @@ -14,12 +14,13 @@ import FlowModuleSleep from './FlowModuleSleep.svelte' import FlowModuleMock from './FlowModuleMock.svelte' import { Play } from 'lucide-svelte' - import type { FlowModule, Job } from '$lib/gen' + import type { FlowModule, Job, WhileloopFlow } from '$lib/gen' import FlowLoopIterationPreview from '$lib/components/FlowLoopIterationPreview.svelte' import FlowModuleDeleteAfterUse from './FlowModuleDeleteAfterUse.svelte' import FlowModuleSkip from './FlowModuleSkip.svelte' import TabsV2 from '$lib/components/common/tabs/TabsV2.svelte' import { useUiIntent } from '$lib/components/copilot/chat/flow/useUiIntent' + import Badge from '$lib/components/common/badge/Badge.svelte' const { flowStateStore } = getContext('FlowEditorContext') @@ -86,7 +87,7 @@ {#if mod.value.type === 'whileloopflow'}
-
+
Skip failures
+
+
Squash + + Beta + This can result in unexpected behavior, use at your own risk for now.
+ Squashing a for loop runs all iterations on the same worker, using a single runner + per step for the entire loop. This eliminates cold starts between iterations for supported + languages (Bun, Deno, and Python). +
+
+
+ { + ;(mod.value as WhileloopFlow).squash = detail + }} + options={{ + right: 'Squash' + }} + class="whitespace-nowrap" + /> +
diff --git a/frontend/src/lib/components/flows/map/MapItem.svelte b/frontend/src/lib/components/flows/map/MapItem.svelte index 08d88f26aa..4e8d6302a2 100644 --- a/frontend/src/lib/components/flows/map/MapItem.svelte +++ b/frontend/src/lib/components/flows/map/MapItem.svelte @@ -164,7 +164,7 @@ mod.summary || (mod.value.type == 'forloopflow' ? 'For loop' : 'While loop') } ${mod.value.parallel ? '(parallel)' : ''} ${ mod.value.skip_failures ? '(skip failures)' : '' - }`} + } ${mod.value.squash ? '(squash)' : ''}`} id={mod.id} on:changeId on:move diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index b724c0acc9..3fcf48b801 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -446,6 +446,8 @@ components: type: boolean parallelism: $ref: "#/components/schemas/InputTransform" + squash: + type: boolean required: - modules - iterator @@ -469,6 +471,8 @@ components: type: boolean parallelism: $ref: "#/components/schemas/InputTransform" + squash: + type: boolean required: - modules - skip_failures From f56f3b0fe6185167e9c4c8541ddefba01c509b8d Mon Sep 17 00:00:00 2001 From: wendrul <53628737+wendrul@users.noreply.github.com> Date: Tue, 25 Nov 2025 18:26:05 +0100 Subject: [PATCH 17/32] fix: workspace forks shouldn't inherit promotion mode repo (#7223) * fix: workspace forks shouldn't inherit promotion mode repo * fix: git sync: don't default to main when talking about target branches in git --- backend/windmill-api/src/workspaces.rs | 9 +++++++-- .../src/lib/components/git_sync/DetectionFlow.svelte | 2 +- .../lib/components/git_sync/GitSyncContext.svelte.ts | 10 ++++++---- .../lib/components/git_sync/GitSyncModeDisplay.svelte | 9 ++++++--- .../components/git_sync/GitSyncRepositoryCard.svelte | 7 ++++--- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index cea6c2ba5c..cd624e7c9d 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -2566,9 +2566,14 @@ async fn update_workspace_settings( WorkspaceGitSyncSettings::default() }; - // We only keep the first git sync repo, since it is considered the main one + // We only keep the first git sync repo that is sync mode (use_individual_branch = false), since it is considered the main one // Context: see WIN-1559 - git_sync_settings.repositories.truncate(1); + git_sync_settings.repositories = git_sync_settings + .repositories + .into_iter() + .filter(|r| !r.use_individual_branch.unwrap_or(false)) + .take(1) + .collect(); let serialized_config = serde_json::to_value::(git_sync_settings) .map_err(|err| Error::internal_err(err.to_string()))?; diff --git a/frontend/src/lib/components/git_sync/DetectionFlow.svelte b/frontend/src/lib/components/git_sync/DetectionFlow.svelte index 817b9942f7..c4b25c8401 100644 --- a/frontend/src/lib/components/git_sync/DetectionFlow.svelte +++ b/frontend/src/lib/components/git_sync/DetectionFlow.svelte @@ -12,7 +12,7 @@ const gitSyncContext = getGitSyncContext() const repo = $derived(gitSyncContext.getRepository(idx)) - let targetBranch = $state('main') + let targetBranch = $state(undefined) // Update target branch when repository changes $effect(() => { diff --git a/frontend/src/lib/components/git_sync/GitSyncContext.svelte.ts b/frontend/src/lib/components/git_sync/GitSyncContext.svelte.ts index 33c2f2fa5c..33b299cba0 100644 --- a/frontend/src/lib/components/git_sync/GitSyncContext.svelte.ts +++ b/frontend/src/lib/components/git_sync/GitSyncContext.svelte.ts @@ -664,12 +664,13 @@ export function createGitSyncContext(workspace: string) { } // Helper to get target branch from git resource - async function getTargetBranch(repo: GitSyncRepository): Promise { + async function getTargetBranch(repo: GitSyncRepository): Promise { if (!repo.git_repo_resource_path) { - return 'main' + return undefined } if (repo._targetBranch) { + if (repo._targetBranch === '') return undefined return repo._targetBranch } @@ -681,14 +682,15 @@ export function createGitSyncContext(workspace: string) { // Extract branch from git resource value const resourceValue = resource.value as any - const targetBranch = resourceValue?.branch || 'main' + const targetBranch = resourceValue?.branch // Cache the result repo._targetBranch = targetBranch + if (targetBranch === '') return undefined return targetBranch } catch (error) { console.warn('Failed to fetch git resource for branch info:', error) - return 'main' + return undefined } } diff --git a/frontend/src/lib/components/git_sync/GitSyncModeDisplay.svelte b/frontend/src/lib/components/git_sync/GitSyncModeDisplay.svelte index 599eb08f4a..94c77a5974 100644 --- a/frontend/src/lib/components/git_sync/GitSyncModeDisplay.svelte +++ b/frontend/src/lib/components/git_sync/GitSyncModeDisplay.svelte @@ -3,7 +3,7 @@ let { mode, targetBranch, repository } = $props<{ mode?: 'sync' | 'promotion' | null - targetBranch: string + targetBranch: string | undefined repository?: GitSyncRepository | null }>() @@ -11,12 +11,15 @@
{#if mode === 'promotion'}
Promotion: Creating branches whose promotion target is {targetBranch}
Promotion: Creating branches whose promotion target is {targetBranch? `'${targetBranch}'` : + "the repo's default branch"}
{#if repository?.group_by_folder}
Grouped by folder
{/if} + {:else if targetBranch} +
Sync: Syncing back to branch '{targetBranch}'
{:else} -
Sync: Syncing back to branch {targetBranch}
+
Sync: Syncing back to the repo's default branch
{/if}
diff --git a/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte b/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte index c5700622d4..6d8bd34919 100644 --- a/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte +++ b/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte @@ -50,7 +50,7 @@ const validation = $derived(idx !== null ? gitSyncContext.getValidation(idx) : null) const gitSyncTestJob = $derived(idx !== null ? gitSyncContext.gitSyncTestJobs?.[idx] : null) let confirmingDelete = $state(false) - let targetBranch = $state('main') // Default to main, will be updated when resource is available + let targetBranch = $state(undefined) // Default to main, will be updated when resource is available // Update target branch when repository changes $effect(() => { @@ -108,12 +108,13 @@ ) // Determine display description based on variant and mode + const targetOrDefaultBranch = $derived(targetBranch ? `'${targetBranch}'` : 'repo\'s default' ) const displayDescription = $derived( variant === 'primary-sync' || variant === 'primary-promotion' ? mode === 'sync' - ? `Changes will be committed directly to the ${targetBranch} branch` + ? `Changes will be committed directly to the ${targetOrDefaultBranch} branch` : mode === 'promotion' - ? `Changes will be made to new branches whose promotion target is ${targetBranch}` + ? `Changes will be made to new branches whose promotion target is the ${targetOrDefaultBranch} branch` : null : null ) From f8a0bfc20d1ccb6ce36e3adf4188533470270bdb Mon Sep 17 00:00:00 2001 From: hugocasa Date: Tue, 25 Nov 2025 19:22:34 +0100 Subject: [PATCH 18/32] feat(frontend): move app reports script to hub (#7227) --- .../apps/editor/AppReportsDrawerInner.svelte | 72 +------------------ frontend/src/lib/hub.ts | 1 + frontend/src/lib/hubPaths.json | 1 + 3 files changed, 5 insertions(+), 69 deletions(-) diff --git a/frontend/src/lib/components/apps/editor/AppReportsDrawerInner.svelte b/frontend/src/lib/components/apps/editor/AppReportsDrawerInner.svelte index 40c72b061d..3f25cca3b0 100644 --- a/frontend/src/lib/components/apps/editor/AppReportsDrawerInner.svelte +++ b/frontend/src/lib/components/apps/editor/AppReportsDrawerInner.svelte @@ -159,71 +159,6 @@ sendUserToast('App reporting disabled') } - const appPreviewScript = `import puppeteer from 'puppeteer-core'; -import dayjs from 'dayjs'; -export async function main( - app_path: string, - startup_duration = 5, - kind: 'pdf' | 'png' = 'pdf', - customWidth: null | number, - customHeight: null | number, -) { - let browser = null - try { - browser = await puppeteer.launch({ headless: true, executablePath: '/usr/bin/chromium', args: ['--no-sandbox', - '--no-zygote', - '--disable-setuid-sandbox', - '--disable-dev-shm-usage', - '--disable-gpu'] }); - const page = await browser.newPage(); - await page.setCookie({ - "name": "token", - "value": Bun.env["WM_TOKEN"], - "domain": Bun.env["BASE_URL"]?.replace(/https?:\\/\\//, '') - }) - page - .on('console', msg => - console.log(dayjs().format("HH:mm:ss") + " " + msg.type().substr(0, 3).toUpperCase() + " " + msg.text())) - .on('pageerror', ({ msg }) => console.log(dayjs().format("HH:mm:ss") + " " + msg)); - await page.setViewport({ width: 1200, height: 2000 }); - await page.goto(Bun.env["BASE_URL"] + '/apps/get/' + app_path + '?workspace=' + Bun.env["WM_WORKSPACE"] + "&hideRefreshBar=true&hideEditBtn=true"); - await page.waitForSelector("#app-content", { timeout: 20000 }) - - const elem = await page.$('#app-content'); - let width: null | number = customWidth || 1200 - let height: null | number = customHeight || (await elem.boundingBox()).height - await page.setViewport({ width, height }); - await new Promise((resolve, _) => { - setTimeout(resolve, startup_duration * 1000) - }) - try { - await page.$eval("#sidebar", el => el.remove()) - } catch {} - await page.$eval("#content", el => el.classList.remove("md:pl-12")) - await page.$$eval(".app-component-refresh-btn", els => els.forEach(el => el.remove())) - await page.$$eval(".app-table-footer-btn", els => els.forEach(el => el.remove())) - - await new Promise((resolve, _) => setTimeout(resolve, 500)) - - const screenshot = kind === "pdf" ? await page.pdf({ - printBackground: true, - width, - height - }) : await page.screenshot({ - fullPage: true, - type: "png", - captureBeyondViewport: false - }); - await browser.close(); - return Buffer.from(screenshot).toString('base64'); - } catch (err) { - if (browser) { - await browser.close(); - } - throw err; - } -}` - const notificationScripts = { discord: { path: hubPaths.discordReport, @@ -347,10 +282,9 @@ export async function main( { id: 'a', value: { - type: 'rawscript' as const, - tag: 'chromium', - content: appPreviewScript, - language: 'bun' as const, + type: 'script' as const, + tag_override: 'chromium', + path: hubPaths.appReport, input_transforms: { app_path: { expr: 'flow_input.app_path', diff --git a/frontend/src/lib/hub.ts b/frontend/src/lib/hub.ts index 13e702a2bf..78a617397b 100644 --- a/frontend/src/lib/hub.ts +++ b/frontend/src/lib/hub.ts @@ -98,6 +98,7 @@ type HubPaths = { teamsSuccessHandler: string emailErrorHandler: string cloneRepoToS3forGitRepoViewer: string + appReport: string } export const hubPaths = JSON.parse(rawHubPaths) as HubPaths diff --git a/frontend/src/lib/hubPaths.json b/frontend/src/lib/hubPaths.json index e5244469ea..f336843ffe 100644 --- a/frontend/src/lib/hubPaths.json +++ b/frontend/src/lib/hubPaths.json @@ -39,6 +39,7 @@ "slackReport": "hub/9084/slack", "discordReport": "hub/9085/discord", "smtpReport": "hub/9086/smtp", + "appReport": "hub/28076/app-report", "cloneRepoToS3forGitRepoViewer_0": "hub/19825/clone_repo_and_upload_to_instance_storage", "cloneRepoToS3forGitRepoViewer": "hub/19827/clone_repo_and_upload_to_instance_storage" } From cba9552e2fea38f527fadc6af217248dfbd48011 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 26 Nov 2025 07:37:05 +0000 Subject: [PATCH 19/32] cookie_domain impacts csrf cookie name --- backend/ee-repo-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index bc6e0fecec..a73d73713d 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -f9434efa127dadb0a04c87d6fc368cc289d93501 +1191204c415e86d429ec0ea9d67c0a9c94af7894 \ No newline at end of file From 8d00730c90fa49a1488c07489ec5d7ae9d19e1c5 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:56:46 +0100 Subject: [PATCH 20/32] fix $app.darkMode not set (#7230) --- frontend/src/lib/components/apps/editor/AppEditorHeader.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index 38da3ab9c1..82a08668cc 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -676,6 +676,7 @@ document.documentElement.classList.remove('dark') } $darkMode = newDarkMode ?? globalDarkMode + $app.darkMode = newDarkMode } let priorDarkMode = document.documentElement.classList.contains('dark') From c0a92f83b00341b0eee36e2dc88d301a75b6fdfb Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 26 Nov 2025 11:00:59 +0000 Subject: [PATCH 21/32] fix(cli): improve back-compatibility with app.yaml with policy still present --- cli/src/commands/app/apps.ts | 9 +++++++-- cli/src/commands/sync/sync.ts | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cli/src/commands/app/apps.ts b/cli/src/commands/app/apps.ts index 0fefd7afbc..9ed1c0d158 100644 --- a/cli/src/commands/app/apps.ts +++ b/cli/src/commands/app/apps.ts @@ -25,6 +25,9 @@ export interface AppFile { const alreadySynced: string[] = []; +export function isExecutionModeAnonymous(app: any) { + return app?.["policy"]?.["execution_mode"] == "anonymous"; +} export async function pushApp( workspace: string, remotePath: string, @@ -46,7 +49,7 @@ export async function pushApp( } catch { //ignore } - if (app?.["policy"]?.["execution_mode"] == "anonymous") { + if (isExecutionModeAnonymous(app)) { app.public = true; } // console.log(app); @@ -85,7 +88,9 @@ export async function pushApp( } replaceInlineScripts(localApp.value); - await generatingPolicy(localApp, remotePath, localApp?.["public"] ?? false); + // console.log(localApp, localApp?.["policy"]); + await generatingPolicy(localApp, remotePath, localApp?.["public"] ?? (localApp.policy ? isExecutionModeAnonymous(localApp) : false)); + // console.log(localApp, localApp?.["policy"]); if (app) { if (isSuperset(localApp, app)) { log.info(colors.green(`App ${remotePath} is up to date`)); diff --git a/cli/src/commands/sync/sync.ts b/cli/src/commands/sync/sync.ts index d145b03490..3ea6ced18c 100644 --- a/cli/src/commands/sync/sync.ts +++ b/cli/src/commands/sync/sync.ts @@ -67,6 +67,7 @@ import { PathAssigner, } from "../../../windmill-utils-internal/src/path-utils/path-assigner.ts"; import { extractInlineScripts as extractInlineScriptsForFlows } from "../../../windmill-utils-internal/src/inline-scripts/extractor.ts"; +import { isExecutionModeAnonymous } from "../app/apps.ts"; // Merge CLI options with effective settings, preserving CLI flags as overrides function mergeCliWithEffectiveOptions< @@ -415,7 +416,7 @@ function ZipFSElement( }; } - if (app?.["policy"]?.["execution_mode"] == "anonymous") { + if (isExecutionModeAnonymous(app)) { app.public = true; } app.policy = undefined; From 8922be11a6935d200e1909f14aa410c6eff67a13 Mon Sep 17 00:00:00 2001 From: hugocasa Date: Wed, 26 Nov 2025 12:02:21 +0100 Subject: [PATCH 22/32] fix(frontend): workspace color race condition for superadmins (#7229) --- ...3cebdf8d777f48e148bcb171fa15e8bf6f098.json | 58 +++++++++++++++++++ backend/windmill-api/openapi.yaml | 16 +++++ backend/windmill-api/src/workspaces.rs | 41 ++++++++++++- frontend/src/lib/stores.ts | 28 ++++++--- 4 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json diff --git a/backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json b/backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json new file mode 100644 index 0000000000..72942b3788 --- /dev/null +++ b/backend/.sqlx/query-00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098.json @@ -0,0 +1,58 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n workspace.id AS \"id!\",\n workspace.name AS \"name!\",\n workspace.owner AS \"owner!\",\n workspace.deleted AS \"deleted!\",\n workspace.premium AS \"premium!\",\n workspace_settings.color AS \"color\",\n workspace.parent_workspace_id AS \"parent_workspace_id\"\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n WHERE workspace.id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id!", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "name!", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "owner!", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "deleted!", + "type_info": "Bool" + }, + { + "ordinal": 4, + "name": "premium!", + "type_info": "Bool" + }, + { + "ordinal": 5, + "name": "color", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "parent_workspace_id", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + true + ] + }, + "hash": "00c1dd0cfaf15aafdcfcabc1f123cebdf8d777f48e148bcb171fa15e8bf6f098" +} diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 139c6f325a..9ce19ef33a 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -688,6 +688,22 @@ paths: schema: $ref: "#/components/schemas/UserWorkspaceList" + /w/{workspace}/workspaces/get_as_superadmin: + get: + summary: get workspace as super admin (require to be super admin) + operationId: getWorkspaceAsSuperAdmin + tags: + - workspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: workspace + content: + application/json: + schema: + $ref: "#/components/schemas/Workspace" + /workspaces/list_as_superadmin: get: summary: list all workspaces as super admin (require to be super admin) diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index cd624e7c9d..ebc53eb733 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -50,7 +50,7 @@ use windmill_common::{ oauth2::WORKSPACE_SLACK_BOT_TOKEN_PATH, utils::{paginate, rd_string, require_admin, Pagination}, }; -use windmill_git_sync::{handle_fork_branch_creation, handle_deployment_metadata, DeployedObject}; +use windmill_git_sync::{handle_deployment_metadata, handle_fork_branch_creation, DeployedObject}; use windmill_worker::scoped_dependency_map::{DependencyMap, ScopedDependencyMap}; #[cfg(feature = "enterprise")] @@ -73,6 +73,7 @@ lazy_static::lazy_static! { pub fn workspaced_service() -> Router { let router = Router::new() + .route("/get_as_superadmin", get(get_workspace_as_superadmin)) .route("/list_pending_invites", get(list_pending_invites)) .route("/update", post(edit_workspace)) .route("/archive", post(archive_workspace)) @@ -163,7 +164,10 @@ pub fn workspaced_service() -> Router { post(acknowledge_all_critical_alerts), ) .route("/critical_alerts/mute", post(mute_critical_alerts)) - .route("/create_workspace_fork_branch", post(create_workspace_fork_branch)) + .route( + "/create_workspace_fork_branch", + post(create_workspace_fork_branch), + ) .route("/operator_settings", post(update_operator_settings)); #[cfg(all(feature = "stripe", feature = "enterprise"))] @@ -706,7 +710,9 @@ async fn get_slack_oauth_config( .await?; // Mask the secret if it exists - let masked_secret = settings.slack_oauth_client_secret.map(|_| "***".to_string()); + let masked_secret = settings + .slack_oauth_client_secret + .map(|_| "***".to_string()); Ok(Json(GetSlackOAuthConfigResponse { slack_oauth_client_id: settings.slack_oauth_client_id, @@ -2227,6 +2233,35 @@ async fn get_used_triggers( Ok(Json(websocket_used)) } +async fn get_workspace_as_superadmin( + authed: ApiAuthed, + Extension(db): Extension, + Path(w_id): Path, +) -> JsonResult { + require_super_admin(&db, &authed.email).await?; + let workspace = sqlx::query_as!( + Workspace, + "SELECT + workspace.id AS \"id!\", + workspace.name AS \"name!\", + workspace.owner AS \"owner!\", + workspace.deleted AS \"deleted!\", + workspace.premium AS \"premium!\", + workspace_settings.color AS \"color\", + workspace.parent_workspace_id AS \"parent_workspace_id\" + FROM workspace + LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id + WHERE workspace.id = $1", + w_id + ) + .fetch_optional(&db) + .await?; + + let workspace = not_found_if_none(workspace, "workspace", w_id)?; + + Ok(Json(workspace)) +} + async fn list_workspaces_as_super_admin( authed: ApiAuthed, Extension(db): Extension, diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index 91ecfd1262..5632bff47a 100644 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -3,9 +3,11 @@ import { derived, type Readable, writable } from 'svelte/store' import type { IntrospectionQuery } from 'graphql' import { + CancelablePromise, type OperatorSettings, type TokenResponse, type UserWorkspaceList, + type Workspace, type WorkspaceDefaultScripts, WorkspaceService } from './gen' @@ -168,32 +170,40 @@ export const instanceSettingsSelectedTab = writable('Core') export const isCriticalAlertsUIOpen = writable(false) +let getWorkspacePromise: CancelablePromise | null = null export const workspaceColor: Readable = derived( [workspaceStore, usersWorkspaceStore, superadmin], ([workspaceStore, usersWorkspaceStore, superadmin], set: (value: string | undefined) => void) => { - if (!workspaceStore) { - set(undefined) + if (!workspaceStore || !usersWorkspaceStore) { return } // First try to get the color from usersWorkspaceStore - const color = usersWorkspaceStore?.workspaces.find((w) => w.id === workspaceStore)?.color + const workspace = usersWorkspaceStore.workspaces.find((w) => w.id === workspaceStore) - if (color) { - set(color) + if (workspace) { + set(workspace.color) return } - // If not found and user is superadmin, try to get it from superadmin list + // If workspace not found and user is superadmin, get it as superadmin if (!superadmin) { set(undefined) return } - WorkspaceService.listWorkspacesAsSuperAdmin().then((workspaces) => { - const superadminColor = workspaces.find((w) => w.id === workspaceStore)?.color - set(superadminColor) + getWorkspacePromise?.cancel() + + getWorkspacePromise = WorkspaceService.getWorkspaceAsSuperAdmin({ + workspace: workspaceStore }) + + getWorkspacePromise + .then((workspace) => set(workspace.color)) + .catch((error) => { + console.error('error getting workspace as superadmin', error) + set(undefined) + }) } ) From d450ab29e16281966e318acc1629f4e52e675422 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 26 Nov 2025 12:09:36 +0100 Subject: [PATCH 23/32] chore(main): release 1.585.0 (#7222) * chore(main): release 1.585.0 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> --- CHANGELOG.md | 15 +++++ backend/Cargo.lock | 66 +++++++++---------- backend/Cargo.toml | 4 +- backend/windmill-api/openapi.yaml | 2 +- benchmarks/lib.ts | 2 +- cli/src/main.ts | 2 +- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- lsp/Pipfile | 4 +- openflow.openapi.yaml | 2 +- .../WindmillClient/WindmillClient.psd1 | 2 +- python-client/wmill/pyproject.toml | 2 +- python-client/wmill_pg/pyproject.toml | 2 +- typescript-client/jsr.json | 2 +- typescript-client/package.json | 2 +- version.txt | 2 +- 16 files changed, 65 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d65463af95..4944da2051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [1.585.0](https://github.com/windmill-labs/windmill/compare/v1.584.0...v1.585.0) (2025-11-26) + + +### Features + +* flow for loop squashing ([#7107](https://github.com/windmill-labs/windmill/issues/7107)) ([93c34c6](https://github.com/windmill-labs/windmill/commit/93c34c6d769dd56da02064c0abdaa060efe0259d)) +* **frontend:** move app reports script to hub ([#7227](https://github.com/windmill-labs/windmill/issues/7227)) ([f8a0bfc](https://github.com/windmill-labs/windmill/commit/f8a0bfc20d1ccb6ce36e3adf4188533470270bdb)) + + +### Bug Fixes + +* **cli:** improve back-compatibility with app.yaml with policy still present ([c0a92f8](https://github.com/windmill-labs/windmill/commit/c0a92f83b00341b0eee36e2dc88d301a75b6fdfb)) +* **frontend:** workspace color race condition for superadmins ([#7229](https://github.com/windmill-labs/windmill/issues/7229)) ([8922be1](https://github.com/windmill-labs/windmill/commit/8922be11a6935d200e1909f14aa410c6eff67a13)) +* workspace forks shouldn't inherit promotion mode repo ([#7223](https://github.com/windmill-labs/windmill/issues/7223)) ([f56f3b0](https://github.com/windmill-labs/windmill/commit/f56f3b0fe6185167e9c4c8541ddefba01c509b8d)) + ## [1.584.0](https://github.com/windmill-labs/windmill/compare/v1.583.3...v1.584.0) (2025-11-25) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index cce1bb1039..9463e75efd 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1688,9 +1688,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", "cfg_aliases 0.2.1", @@ -1698,9 +1698,9 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", @@ -14155,9 +14155,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", "valuable", @@ -15210,7 +15210,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "aws-sdk-config", @@ -15272,7 +15272,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "argon2", @@ -15393,7 +15393,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.584.0" +version = "1.585.0" dependencies = [ "base64 0.22.1", "chrono", @@ -15408,7 +15408,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.584.0" +version = "1.585.0" dependencies = [ "chrono", "lazy_static", @@ -15422,7 +15422,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "axum", @@ -15441,7 +15441,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "async-recursion", @@ -15530,7 +15530,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.584.0" +version = "1.585.0" dependencies = [ "regex", "serde", @@ -15545,7 +15545,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "bytes", @@ -15569,7 +15569,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.584.0" +version = "1.585.0" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -15581,7 +15581,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.584.0" +version = "1.585.0" dependencies = [ "convert_case 0.6.0", "serde", @@ -15590,7 +15590,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "lazy_static", @@ -15602,7 +15602,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "serde_json", @@ -15614,7 +15614,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "gosyn", @@ -15626,7 +15626,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "lazy_static", @@ -15638,7 +15638,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "serde_json", @@ -15650,7 +15650,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "nu-parser", @@ -15661,7 +15661,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15672,7 +15672,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15684,7 +15684,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "async-recursion", @@ -15707,7 +15707,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "lazy_static", @@ -15721,7 +15721,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15738,7 +15738,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "lazy_static", @@ -15752,7 +15752,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "lazy_static", @@ -15770,7 +15770,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "serde", @@ -15781,7 +15781,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "async-recursion", @@ -15818,7 +15818,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.584.0" +version = "1.585.0" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15828,7 +15828,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.584.0" +version = "1.585.0" dependencies = [ "anyhow", "async-once-cell", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index d533d32549..05c86807be 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.584.0" +version = "1.585.0" authors.workspace = true edition.workspace = true @@ -33,7 +33,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.584.0" +version = "1.585.0" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 9ce19ef33a..339df53205 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.584.0 + version: 1.585.0 title: Windmill API contact: diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index 5dc61d56a7..a936855fe2 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -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.584.0"; +export const VERSION = "v1.585.0"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/src/main.ts b/cli/src/main.ts index 4430410890..4f0f455522 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.584.0"; +export const VERSION = "1.585.0"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 14868d1907..a0527f34f7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.584.0", + "version": "1.585.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.584.0", + "version": "1.585.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 58a5be9fdb..a1c0c39cbe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.584.0", + "version": "1.585.0", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/lsp/Pipfile b/lsp/Pipfile index a535d7580a..d3f2ccb54e 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.584.0" -wmill_pg = ">=1.584.0" +wmill = ">=1.585.0" +wmill_pg = ">=1.585.0" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 3fcf48b801..cd534f3fac 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.584.0 + version: 1.585.0 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index fa0d0e6afa..ffe3220eb2 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.584.0' + ModuleVersion = '1.585.0' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 4a9cabadc7..73e5cf3026 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.584.0" +version = "1.585.0" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index 7b9653640e..2732b66b10 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.584.0" +version = "1.585.0" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index f4bfe59424..908424b59f 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.584.0", + "version": "1.585.0", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index bfe2a641b8..5afa72aaf9 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.584.0", + "version": "1.585.0", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index a224cb38e3..30d77f1213 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.584.0 +1.585.0 From 67895abc9f08f5278cf907b8a22bfc79c2da696e Mon Sep 17 00:00:00 2001 From: HugoCasa Date: Wed, 26 Nov 2025 16:19:55 +0100 Subject: [PATCH 24/32] add option to build wasm packages for nodejs --- backend/parsers/windmill-parser-wasm/build.nu | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/backend/parsers/windmill-parser-wasm/build.nu b/backend/parsers/windmill-parser-wasm/build.nu index 7c3bf9d4a6..d954366113 100755 --- a/backend/parsers/windmill-parser-wasm/build.nu +++ b/backend/parsers/windmill-parser-wasm/build.nu @@ -65,15 +65,19 @@ const targets = [ # -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort # Build all separately -def 'main all' [ --no-opt(-n), --cli] { +def 'main all' [ --no-opt(-n), --cli, --node ] { if ($no_opt) { - if ($cli) { + if ($node) { + $targets | each { main $in.ident -n --node } + } else if ($cli) { $targets | each { main $in.ident -n --cli } } else { $targets | each { main $in.ident -n } } } else { - if ($cli) { + if ($node) { + $targets | each { main $in.ident --node } + } else if ($cli) { $targets | each { main $in.ident --cli } } else { $targets | each { main $in.ident } @@ -86,6 +90,7 @@ def main [ target: string, # Language, e.g.: py, ts, rust --no-opt(-n), # Compile in debug mode for dev --cli # Compile and place binaries in cli. + --node ] { let t = $targets | where ident == $target; @@ -97,7 +102,10 @@ def main [ mut profile = ""; mut tar = ""; - if ($cli) { + if ($node) { + $env.OUT_DIR = $"node-pkg-($t.ident)" + $tar = "nodejs" + } else if ($cli) { $env.OUT_DIR = $"../../../cli/wasm/($t.ident)" $tar = "deno" } else { From a573e6de950cc72f4951328321aecd814cb8eecb Mon Sep 17 00:00:00 2001 From: HugoCasa Date: Wed, 26 Nov 2025 17:07:50 +0100 Subject: [PATCH 25/32] chore: update cli versions in git sync scripts --- frontend/src/lib/hubPaths.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/hubPaths.json b/frontend/src/lib/hubPaths.json index f336843ffe..80ec7eff19 100644 --- a/frontend/src/lib/hubPaths.json +++ b/frontend/src/lib/hubPaths.json @@ -16,7 +16,8 @@ "gitSync_14": "hub/19803/sync-script-to-git-repo-windmill", "gitSync_15": "hub/19816/sync-script-to-git-repo-windmill", "gitSync_16": "hub/19818/sync-script-to-git-repo-windmill", - "gitSync": "hub/28073/sync-script-to-git-repo-windmill", + "gitSync_17": "hub/28073/sync-script-to-git-repo-windmill", + "gitSync": "hub/28078/sync-script-to-git-repo-windmill", "gitSyncTest_0": "hub/9073/git-repo-test-read-write-windmill", "gitSyncTest_1": "hub/11499/git-repo-test-read-write-windmill", "gitSyncTest_2": "hub/11667/git-repo-test-read-write-windmill", @@ -25,7 +26,8 @@ "gitInitRepo_0": "hub/19787/git-sync%3A-init-repository-windmill", "gitInitRepo_1": "hub/19797/git-sync%3A-init-repository-windmill", "gitInitRepo_2": "hub/19817/git-sync%3A-init-repository-windmill", - "gitInitRepo": "hub/28072/git-sync%3A-init-repository-windmill", + "gitInitRepo_3": "hub/28072/git-sync%3A-init-repository-windmill", + "gitInitRepo": "hub/28077/git-sync%3A-init-repository-windmill", "slackErrorHandler": "hub/19741/workspace-or-schedule-error-handler-slack", "slackErrorHandler_0": "hub/9079/workspace-or-schedule-error-handler-slack", "slackErrorHandler_1": "hub/9206/workspace-or-schedule-error-handler-slack", From 3f9dae39c9eed4f338cec82d07af442f43612081 Mon Sep 17 00:00:00 2001 From: hugocasa Date: Wed, 26 Nov 2025 20:48:13 +0100 Subject: [PATCH 26/32] fix build (#7233) * fix build * Update ee-repo-ref.txt --------- Co-authored-by: windmill-internal-app[bot] --- backend/ee-repo-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index a73d73713d..2a3de2d939 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -1191204c415e86d429ec0ea9d67c0a9c94af7894 \ No newline at end of file +99828e4a3a27af428a45d1e6e65092ca15082b1e From faad0006b430262f1ab6b749ccf60a6860a54405 Mon Sep 17 00:00:00 2001 From: wendrul <53628737+wendrul@users.noreply.github.com> Date: Wed, 26 Nov 2025 20:49:12 +0100 Subject: [PATCH 27/32] fix: clone group members on workspace forks (#7232) * Clone usr_to_group table on windmill fork * Update sqlx --- ...3ca8889ea164d9cfb4962997650d922d82f000df9.json | 15 +++++++++++++++ ...4ff3153c43903f929ae5d62fbba12610f89c36d55.json | 2 +- backend/windmill-api/src/workspaces.rs | 11 +++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json diff --git a/backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json b/backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json new file mode 100644 index 0000000000..094331bb82 --- /dev/null +++ b/backend/.sqlx/query-3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO usr_to_group (workspace_id, group_, usr)\n SELECT $2, group_, usr\n FROM usr_to_group\n WHERE workspace_id = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "3f9004b5542afaaef40942a3ca8889ea164d9cfb4962997650d922d82f000df9" +} diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 713ccb9dd3..36ddb8ab9f 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - null + true ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index ebc53eb733..217d48dc7d 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -2678,6 +2678,17 @@ async fn clone_groups( .execute(&mut **tx) .await?; + sqlx::query!( + "INSERT INTO usr_to_group (workspace_id, group_, usr) + SELECT $2, group_, usr + FROM usr_to_group + WHERE workspace_id = $1", + source_workspace_id, + target_workspace_id, + ) + .execute(&mut **tx) + .await?; + Ok(()) } From f7d3d165c5ca8d48ecb9c75eb9db52988470bf43 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 26 Nov 2025 20:54:47 +0100 Subject: [PATCH 28/32] chore(main): release 1.585.1 (#7235) * chore(main): release 1.585.1 * Apply automatic changes --------- Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com> --- CHANGELOG.md | 7 + backend/Cargo.lock | 220 +++++++----------- backend/Cargo.toml | 4 +- backend/windmill-api/openapi.yaml | 2 +- benchmarks/lib.ts | 2 +- cli/src/main.ts | 2 +- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- lsp/Pipfile | 4 +- openflow.openapi.yaml | 2 +- .../WindmillClient/WindmillClient.psd1 | 2 +- python-client/wmill/pyproject.toml | 2 +- python-client/wmill_pg/pyproject.toml | 2 +- typescript-client/jsr.json | 2 +- typescript-client/package.json | 2 +- version.txt | 2 +- 16 files changed, 110 insertions(+), 151 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4944da2051..e4f2ce0b34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.585.1](https://github.com/windmill-labs/windmill/compare/v1.585.0...v1.585.1) (2025-11-26) + + +### Bug Fixes + +* clone group members on workspace forks ([#7232](https://github.com/windmill-labs/windmill/issues/7232)) ([faad000](https://github.com/windmill-labs/windmill/commit/faad0006b430262f1ab6b749ccf60a6860a54405)) + ## [1.585.0](https://github.com/windmill-labs/windmill/compare/v1.584.0...v1.585.0) (2025-11-26) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 9463e75efd..65647da64c 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -2397,9 +2397,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -2747,7 +2747,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.12", + "parking_lot_core", ] [[package]] @@ -2761,7 +2761,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.12", + "parking_lot_core", ] [[package]] @@ -2818,7 +2818,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "parquet", "rand 0.8.5", "regex", @@ -2853,7 +2853,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "tokio", ] @@ -3026,7 +3026,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "parquet", "rand 0.8.5", "tokio", @@ -3051,7 +3051,7 @@ dependencies = [ "futures", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "rand 0.8.5", "tempfile", "url", @@ -3187,7 +3187,7 @@ dependencies = [ "datafusion-common", "datafusion-expr", "datafusion-physical-plan", - "parking_lot 0.12.5", + "parking_lot", "paste", ] @@ -3328,7 +3328,7 @@ dependencies = [ "indexmap 2.11.1", "itertools 0.14.0", "log", - "parking_lot 0.12.5", + "parking_lot", "pin-project-lite", "tokio", ] @@ -3353,7 +3353,7 @@ dependencies = [ "itertools 0.14.0", "log", "object_store", - "parking_lot 0.12.5", + "parking_lot", "tokio", ] @@ -3482,7 +3482,7 @@ dependencies = [ "indexmap 2.11.1", "log", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "serde", "serde_json", "sha2 0.10.9", @@ -3564,7 +3564,7 @@ dependencies = [ "indexmap 2.11.1", "libc", "memoffset", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "pin-project", "serde", @@ -3809,7 +3809,7 @@ dependencies = [ "log", "once_cell", "os_pipe", - "parking_lot 0.12.5", + "parking_lot", "pin-project", "rand 0.8.5", "tokio", @@ -4189,7 +4189,7 @@ dependencies = [ "log", "node_resolver", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "sys_traits", "thiserror 2.0.17", "url", @@ -4346,7 +4346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6742a724e8becb372a74c650a1aefb8924a5b8107f7d75b3848763ea24b27a87" dependencies = [ "futures-util", - "parking_lot 0.12.5", + "parking_lot", "tokio", ] @@ -5590,7 +5590,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.5", + "parking_lot", ] [[package]] @@ -6488,7 +6488,7 @@ dependencies = [ "ipconfig", "moka", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "rand 0.9.0", "resolv-conf", "serde", @@ -7098,18 +7098,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "integer-encoding" version = "3.0.4" @@ -7553,7 +7541,7 @@ dependencies = [ "json-patch", "k8s-openapi", "kube-client", - "parking_lot 0.12.5", + "parking_lot", "pin-project", "serde", "serde_json", @@ -8283,7 +8271,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "equivalent", - "parking_lot 0.12.5", + "parking_lot", "portable-atomic", "rustc_version 0.4.1", "smallvec", @@ -9011,7 +8999,7 @@ dependencies = [ "hyper 1.8.1", "itertools 0.14.0", "md-5 0.10.6", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "quick-xml 0.37.5", "rand 0.9.0", @@ -9430,17 +9418,6 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -9448,21 +9425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core 0.9.12", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -10140,7 +10103,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.5", + "parking_lot", "thiserror 2.0.17", ] @@ -10309,7 +10272,7 @@ dependencies = [ "ahash 0.8.12", "equivalent", "hashbrown 0.16.1", - "parking_lot 0.12.5", + "parking_lot", ] [[package]] @@ -10597,15 +10560,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -10825,9 +10779,9 @@ dependencies = [ [[package]] name = "reqwest-retry" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178" +checksum = "105747e3a037fe5bf17458d794de91149e575b6183fc72c85623a44abb9683f5" dependencies = [ "anyhow", "async-trait", @@ -10835,14 +10789,13 @@ dependencies = [ "getrandom 0.2.16", "http 1.4.0", "hyper 1.8.1", - "parking_lot 0.11.2", "reqwest 0.12.24", "reqwest-middleware", "retry-policies", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", - "wasm-timer", + "wasmtimer", ] [[package]] @@ -10853,9 +10806,9 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "retry-policies" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c" +checksum = "503c78f59814e2664c9980b739b19e40f549233ecf39928040ee54fdd431f614" dependencies = [ "rand 0.8.5", ] @@ -13692,7 +13645,7 @@ dependencies = [ "io-uring", "libc", "mio 1.1.0", - "parking_lot 0.12.5", + "parking_lot", "pin-project-lite", "signal-hook-registry", "slab", @@ -13757,7 +13710,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "phf 0.11.3", "pin-project-lite", @@ -13783,7 +13736,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.5", + "parking_lot", "percent-encoding", "phf 0.11.3", "pin-project-lite", @@ -13979,7 +13932,7 @@ dependencies = [ "indexmap 2.11.1", "toml_datetime 0.7.0", "toml_parser", - "winnow 0.7.13", + "winnow 0.7.14", ] [[package]] @@ -13988,7 +13941,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow 0.7.13", + "winnow 0.7.14", ] [[package]] @@ -14074,7 +14027,7 @@ dependencies = [ "cookie 0.18.1", "futures-util", "http 1.4.0", - "parking_lot 0.12.5", + "parking_lot", "pin-project-lite", "tower-layer", "tower-service", @@ -14132,21 +14085,21 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" dependencies = [ "crossbeam-channel", - "thiserror 1.0.69", + "thiserror 2.0.17", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -14972,21 +14925,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wasm_dep_analyzer" version = "0.2.0" @@ -14997,6 +14935,20 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" version = "0.3.80" @@ -15069,7 +15021,7 @@ dependencies = [ "log", "naga", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "profiling", "raw-window-handle", "ron", @@ -15111,7 +15063,7 @@ dependencies = [ "ndk-sys", "objc", "once_cell", - "parking_lot 0.12.5", + "parking_lot", "profiling", "range-alloc", "raw-window-handle", @@ -15210,7 +15162,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "aws-sdk-config", @@ -15272,7 +15224,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "argon2", @@ -15393,7 +15345,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.585.0" +version = "1.585.1" dependencies = [ "base64 0.22.1", "chrono", @@ -15408,7 +15360,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.585.0" +version = "1.585.1" dependencies = [ "chrono", "lazy_static", @@ -15422,7 +15374,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "axum", @@ -15441,7 +15393,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "async-recursion", @@ -15530,7 +15482,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.585.0" +version = "1.585.1" dependencies = [ "regex", "serde", @@ -15545,7 +15497,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "bytes", @@ -15569,7 +15521,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.585.0" +version = "1.585.1" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -15581,7 +15533,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.585.0" +version = "1.585.1" dependencies = [ "convert_case 0.6.0", "serde", @@ -15590,7 +15542,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15602,7 +15554,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "serde_json", @@ -15614,7 +15566,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "gosyn", @@ -15626,7 +15578,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15638,7 +15590,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "serde_json", @@ -15650,7 +15602,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "nu-parser", @@ -15661,7 +15613,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15672,7 +15624,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15684,7 +15636,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "async-recursion", @@ -15707,7 +15659,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15721,7 +15673,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15738,7 +15690,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15752,7 +15704,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "lazy_static", @@ -15770,7 +15722,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "serde", @@ -15781,7 +15733,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "async-recursion", @@ -15818,7 +15770,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.585.0" +version = "1.585.1" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15828,7 +15780,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.585.0" +version = "1.585.1" dependencies = [ "anyhow", "async-once-cell", @@ -16451,9 +16403,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 05c86807be..dba5305701 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.585.0" +version = "1.585.1" authors.workspace = true edition.workspace = true @@ -33,7 +33,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.585.0" +version = "1.585.1" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 339df53205..deb0f882d3 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.585.0 + version: 1.585.1 title: Windmill API contact: diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index a936855fe2..f94f88118b 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -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.585.0"; +export const VERSION = "v1.585.1"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/src/main.ts b/cli/src/main.ts index 4f0f455522..9f5d05f959 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.585.0"; +export const VERSION = "1.585.1"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a0527f34f7..1c35a6ed17 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.585.0", + "version": "1.585.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.585.0", + "version": "1.585.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index a1c0c39cbe..d5fbfc0d15 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.585.0", + "version": "1.585.1", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/lsp/Pipfile b/lsp/Pipfile index d3f2ccb54e..cd1c2f7c31 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.585.0" -wmill_pg = ">=1.585.0" +wmill = ">=1.585.1" +wmill_pg = ">=1.585.1" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index cd534f3fac..9b58309056 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.585.0 + version: 1.585.1 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index ffe3220eb2..44fe48eec6 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.585.0' + ModuleVersion = '1.585.1' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 73e5cf3026..1bc8342d33 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.585.0" +version = "1.585.1" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index 2732b66b10..309ed062d0 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.585.0" +version = "1.585.1" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 908424b59f..58579bf00d 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.585.0", + "version": "1.585.1", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index 5afa72aaf9..b2a49a5f3a 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.585.0", + "version": "1.585.1", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index 30d77f1213..26ec7f16a6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.585.0 +1.585.1 From eebcbf068d517e5489ccca56137a6df9119b44a1 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 27 Nov 2025 06:08:25 +0000 Subject: [PATCH 29/32] update rolldown-vite to 7.2.8 --- frontend/package-lock.json | 177 +++++++++++++++++-------------------- frontend/package.json | 2 +- 2 files changed, 84 insertions(+), 95 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1c35a6ed17..ca86dea1d7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -142,7 +142,7 @@ "tar": "^7.4.3", "tslib": "^2.6.1", "typescript": "^5.5.0", - "vite": "npm:rolldown-vite@latest", + "vite": "npm:rolldown-vite@7.2.8", "vite-plugin-dts": "^4.5.4", "vite-plugin-mkcert": "^1.17.5", "yootils": "^0.3.1" @@ -1904,9 +1904,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", "dev": true, "license": "MIT", "optional": true, @@ -1916,9 +1916,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", "dev": true, "license": "MIT", "optional": true, @@ -2603,9 +2603,9 @@ } }, "node_modules/@oxc-project/runtime": { - "version": "0.92.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.92.0.tgz", - "integrity": "sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.99.0.tgz", + "integrity": "sha512-8iE5/4OK0SLHqWzRxSvI1gjFPmIH6718s8iwkuco95rBZsCZIHq+5wy4lYsASxnH+8FOhbGndiUrcwsVG5i2zw==", "dev": true, "license": "MIT", "engines": { @@ -2613,9 +2613,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.94.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.94.0.tgz", - "integrity": "sha512-+UgQT/4o59cZfH6Cp7G0hwmqEQ0wE+AdIwhikdwnhWI9Dp8CgSY081+Q3O67/wq3VJu8mgUEB93J9EHHn70fOw==", + "version": "0.99.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.99.0.tgz", + "integrity": "sha512-LLDEhXB7g1m5J+woRSgfKsFPS3LhR9xRhTeIoEBm5WrkwMxn6eZ0Ld0c0K5eHB57ChZX6I3uSmmLjZ8pcjlRcw==", "dev": true, "license": "MIT", "funding": { @@ -2679,9 +2679,9 @@ "license": "SEE LICENSE IN LICENSE" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.42.tgz", - "integrity": "sha512-W5ZKF3TP3bOWuBfotAGp+UGjxOkGV7jRmIRbBA7NFjggx7Oi6vOmGDqpHEIX7kDCiry1cnIsWQaxNvWbMdkvzQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.52.tgz", + "integrity": "sha512-MBGIgysimZPqTDcLXI+i9VveijkP5C3EAncEogXhqfax6YXj1Tr2LY3DVuEOMIjWfMPMhtQSPup4fSTAmgjqIw==", "cpu": [ "arm64" ], @@ -2696,9 +2696,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.42.tgz", - "integrity": "sha512-abw/wtgJA8OCgaTlL+xJxnN/Z01BwV1rfzIp5Hh9x+IIO6xOBfPsQ0nzi0+rWx3TyZ9FZXyC7bbC+5NpQ9EaXQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.52.tgz", + "integrity": "sha512-MmKeoLnKu1d9j6r19K8B+prJnIZ7u+zQ+zGQ3YHXGnr41rzE3eqQLovlkvoZnRoxDGPA4ps0pGiwXy6YE3lJyg==", "cpu": [ "arm64" ], @@ -2713,9 +2713,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.42.tgz", - "integrity": "sha512-Y/UrZIRVr8CvXVEB88t6PeC46r1K9/QdPEo2ASE/b/KBEyXIx+QbM6kv9QfQVWU2Atly2+SVsQzxQsIvuk3lZQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.52.tgz", + "integrity": "sha512-qpHedvQBmIjT8zdnjN3nWPR2qjQyJttbXniCEKKdHeAbZG9HyNPBUzQF7AZZGwmS9coQKL+hWg9FhWzh2dZ2IA==", "cpu": [ "x64" ], @@ -2730,9 +2730,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.42.tgz", - "integrity": "sha512-zRM0oOk7BZiy6DoWBvdV4hyEg+j6+WcBZIMHVirMEZRu8hd18kZdJkg+bjVMfCEhwpWeFUfBfZ1qcaZ5UdYzlQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.52.tgz", + "integrity": "sha512-dDp7WbPapj/NVW0LSiH/CLwMhmLwwKb3R7mh2kWX+QW85X1DGVnIEyKh9PmNJjB/+suG1dJygdtdNPVXK1hylg==", "cpu": [ "x64" ], @@ -2747,9 +2747,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.42.tgz", - "integrity": "sha512-6RjFaC52QNwo7ilU8C5H7swbGlgfTkG9pudXwzr3VYyT18s0C9gLg3mvc7OMPIGqNxnQ0M5lU8j6aQCk2DTRVg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.52.tgz", + "integrity": "sha512-9e4l6vy5qNSliDPqNfR6CkBOAx6PH7iDV4OJiEJzajajGrVy8gc/IKKJUsoE52G8ud8MX6r3PMl97NfwgOzB7g==", "cpu": [ "arm" ], @@ -2764,9 +2764,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.42.tgz", - "integrity": "sha512-LMYHM5Sf6ROq+VUwHMDVX2IAuEsWTv4SnlFEedBnMGpvRuQ14lCmD4m5Q8sjyAQCgyha9oghdGoK8AEg1sXZKg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.52.tgz", + "integrity": "sha512-V48oDR84feRU2KRuzpALp594Uqlx27+zFsT6+BgTcXOtu7dWy350J1G28ydoCwKB+oxwsRPx2e7aeQnmd3YJbQ==", "cpu": [ "arm64" ], @@ -2781,9 +2781,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.42.tgz", - "integrity": "sha512-/bNTYb9aKNhzdbPn3O4MK2aLv55AlrkUKPE4KNfBYjkoZUfDr4jWp7gsSlvTc5A/99V1RCm9axvt616ZzeXGyA==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.52.tgz", + "integrity": "sha512-ENLmSQCWqSA/+YN45V2FqTIemg7QspaiTjlm327eUAMeOLdqmSOVVyrQexJGNTQ5M8sDYCgVAig2Kk01Ggmqaw==", "cpu": [ "arm64" ], @@ -2798,9 +2798,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.42.tgz", - "integrity": "sha512-n/SLa4h342oyeGykZdch7Y3GNCNliRPL4k5wkeZ/5eQZs+c6/ZG1SHCJQoy7bZcmxiMyaXs9HoFmv1PEKrZgWg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.52.tgz", + "integrity": "sha512-klahlb2EIFltSUubn/VLjuc3qxp1E7th8ukayPfdkcKvvYcQ5rJztgx8JsJSuAKVzKtNTqUGOhy4On71BuyV8g==", "cpu": [ "x64" ], @@ -2815,9 +2815,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.42.tgz", - "integrity": "sha512-4PSd46sFzqpLHSGdaSViAb1mk55sCUMpJg+X8ittXaVocQsV3QLG/uydSH8RyL0ngHX5fy3D70LcCzlB15AgHw==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.52.tgz", + "integrity": "sha512-UuA+JqQIgqtkgGN2c/AQ5wi8M6mJHrahz/wciENPTeI6zEIbbLGoth5XN+sQe2pJDejEVofN9aOAp0kaazwnVg==", "cpu": [ "x64" ], @@ -2832,9 +2832,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.42.tgz", - "integrity": "sha512-BmWoeJJyeZXmZBcfoxG6J9+rl2G7eO47qdTkAzEegj4n3aC6CBIHOuDcbE8BvhZaEjQR0nh0nJrtEDlt65Q7Sw==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.52.tgz", + "integrity": "sha512-1BNQW8u4ro8bsN1+tgKENJiqmvc+WfuaUhXzMImOVSMw28pkBKdfZtX2qJPADV3terx+vNJtlsgSGeb3+W6Jiw==", "cpu": [ "arm64" ], @@ -2849,9 +2849,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.42.tgz", - "integrity": "sha512-2Ft32F7uiDTrGZUKws6CLNTlvTWHC33l4vpXrzUucf9rYtUThAdPCOt89Pmn13tNX6AulxjGEP2R0nZjTSW3eQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.52.tgz", + "integrity": "sha512-K/p7clhCqJOQpXGykrFaBX2Dp9AUVIDHGc+PtFGBwg7V+mvBTv/tsm3LC3aUmH02H2y3gz4y+nUTQ0MLpofEEg==", "cpu": [ "wasm32" ], @@ -2859,16 +2859,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.6" + "@napi-rs/wasm-runtime": "^1.0.7" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.42.tgz", - "integrity": "sha512-hC1kShXW/z221eG+WzQMN06KepvPbMBknF0iGR3VMYJLOe9gwnSTfGxFT5hf8XrPv7CEZqTWRd0GQpkSHRbGsw==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.52.tgz", + "integrity": "sha512-a4EkXBtnYYsKipjS7QOhEBM4bU5IlR9N1hU+JcVEVeuTiaslIyhWVKsvf7K2YkQHyVAJ+7/A9BtrGqORFcTgng==", "cpu": [ "arm64" ], @@ -2883,9 +2883,9 @@ } }, "node_modules/@rolldown/binding-win32-ia32-msvc": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.42.tgz", - "integrity": "sha512-AICBYromawouGjj+GS33369E8Vwhy6UwhQEhQ5evfS8jPCsyVvoICJatbDGDGH01dwtVGLD5eDFzPicUOVpe4g==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.52.tgz", + "integrity": "sha512-5ZXcYyd4GxPA6QfbGrNcQjmjbuLGvfz6728pZMsQvGHI+06LT06M6TPtXvFvLgXtexc+OqvFe1yAIXJU1gob/w==", "cpu": [ "ia32" ], @@ -2900,9 +2900,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.42.tgz", - "integrity": "sha512-XpZ0M+tjoEiSc9c+uZR7FCnOI0uxDRNs1elGOMjeB0pUP1QmvVbZGYNsyLbLoP4u7e3VQN8rie1OQ8/mB6rcJg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.52.tgz", + "integrity": "sha512-tzpnRQXJrSzb8Z9sm97UD3cY0toKOImx+xRKsDLX4zHaAlRXWh7jbaKBePJXEN7gNw7Nm03PBNwphdtA8KSUYQ==", "cpu": [ "x64" ], @@ -2917,9 +2917,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.42.tgz", - "integrity": "sha512-N7pQzk9CyE7q0bBN/q0J8s6Db279r5kUZc6d7/wWRe9/zXqC52HQovVyu6iXPIDY4BEzzgbVLhVFXrOuGJ22ZQ==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.52.tgz", + "integrity": "sha512-/L0htLJZbaZFL1g9OHOblTxbCYIGefErJjtYOwgl9ZqNx27P3L0SDfjhhHIss32gu5NWgnxuT2a2Hnnv6QGHKA==", "dev": true, "license": "MIT" }, @@ -4437,16 +4437,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", - "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - } - }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -12260,15 +12250,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-beta.42", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.42.tgz", - "integrity": "sha512-xaPcckj+BbJhYLsv8gOqezc8EdMcKKe/gk8v47B0KPvgABDrQ0qmNPAiT/gh9n9Foe0bUkEv2qzj42uU5q1WRg==", + "version": "1.0.0-beta.52", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.52.tgz", + "integrity": "sha512-Hbnpljue+JhMJrlOjQ1ixp9me7sUec7OjFvS+A1Qm8k8Xyxmw3ZhxFu7LlSXW1s9AX3POE9W9o2oqCEeR5uDmg==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.94.0", - "@rolldown/pluginutils": "1.0.0-beta.42", - "ansis": "=4.2.0" + "@oxc-project/types": "=0.99.0", + "@rolldown/pluginutils": "1.0.0-beta.52" }, "bin": { "rolldown": "bin/cli.mjs" @@ -12277,20 +12266,20 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-beta.42", - "@rolldown/binding-darwin-arm64": "1.0.0-beta.42", - "@rolldown/binding-darwin-x64": "1.0.0-beta.42", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.42", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.42", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.42", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.42", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.42", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.42", - "@rolldown/binding-openharmony-arm64": "1.0.0-beta.42", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.42", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.42", - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.42", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.42" + "@rolldown/binding-android-arm64": "1.0.0-beta.52", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.52", + "@rolldown/binding-darwin-x64": "1.0.0-beta.52", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.52", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.52", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.52", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.52", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.52", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.52", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.52", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.52", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.52", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.52", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.52" } }, "node_modules/run-parallel": { @@ -14130,18 +14119,18 @@ }, "node_modules/vite": { "name": "rolldown-vite", - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.1.16.tgz", - "integrity": "sha512-cK6tCmZyEC0KRAcXTjQ+ara+wkqmaE7WUoI0ZfZzDuvaRaZ3mtvbhTJc4cH+PjKRok++++Z1bZZaNlf3+SnnGA==", + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.2.8.tgz", + "integrity": "sha512-8wKihlF6EDF8grimwd7GPOhLkQkSIgj6Hlcp0CXhtO3HAXeUUqhgZmJmn07OF8e4PbTusMX6Yxmy1BptVRZsdw==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/runtime": "0.92.0", + "@oxc-project/runtime": "0.99.0", "fdir": "^6.5.0", "lightningcss": "^1.30.2", "picomatch": "^4.0.3", "postcss": "^8.5.6", - "rolldown": "1.0.0-beta.42", + "rolldown": "1.0.0-beta.52", "tinyglobby": "^0.2.15" }, "bin": { diff --git a/frontend/package.json b/frontend/package.json index d5fbfc0d15..7c3340235c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -65,7 +65,7 @@ "tar": "^7.4.3", "tslib": "^2.6.1", "typescript": "^5.5.0", - "vite": "npm:rolldown-vite@latest", + "vite": "npm:rolldown-vite@7.2.8", "vite-plugin-dts": "^4.5.4", "vite-plugin-mkcert": "^1.17.5", "yootils": "^0.3.1" From 4639a5f9d9cb73c3729f057e6f7bc9a7e6f30802 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 27 Nov 2025 06:41:20 +0000 Subject: [PATCH 30/32] fix ol use --- frontend/src/lib/components/MapResult.svelte | 12 ++++++------ .../components/apps/components/display/AppMap.svelte | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/src/lib/components/MapResult.svelte b/frontend/src/lib/components/MapResult.svelte index 60a33c8a66..a6851e9082 100644 --- a/frontend/src/lib/components/MapResult.svelte +++ b/frontend/src/lib/components/MapResult.svelte @@ -1,12 +1,12 @@