mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-04 16:03:06 +00:00
Merge branch 'main' into alp/msft_teams
This commit is contained in:
@@ -1,5 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
## [1.448.0](https://github.com/windmill-labs/windmill/compare/v1.447.6...v1.448.0) (2025-01-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Migrate to bun.lock ([#5112](https://github.com/windmill-labs/windmill/issues/5112)) ([fcfad69](https://github.com/windmill-labs/windmill/commit/fcfad69195a776d4958c035dca16100368966a66))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve workspace specific tags behavior ([669a1ff](https://github.com/windmill-labs/windmill/commit/669a1ff8e6ab782ce1168170db684deb5f0ec99a))
|
||||
* improve workspace specific tags behavior ([e81c2c9](https://github.com/windmill-labs/windmill/commit/e81c2c983d139cd24e983f6a76de56c10a694954))
|
||||
|
||||
## [1.447.6](https://github.com/windmill-labs/windmill/compare/v1.447.5...v1.447.6) (2025-01-21)
|
||||
|
||||
|
||||
|
||||
Generated
+65
-65
@@ -713,14 +713,14 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sso"
|
||||
version = "1.54.0"
|
||||
version = "1.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "921a13ed6aabe2d1258f65ef7804946255c799224440774c30e1a2c65cdf983a"
|
||||
checksum = "33993c0b054f4251ff2946941b56c26b582677303eeca34087594eb901ece022"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -740,9 +740,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-ssooidc"
|
||||
version = "1.55.0"
|
||||
version = "1.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "196c952738b05dfc917d82a3e9b5ba850822a6d6a86d677afda2a156cc172ceb"
|
||||
checksum = "3bd3ceba74a584337a8f3839c818f14f1a2288bfd24235120ff22d7e17a0dd54"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -762,9 +762,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-sts"
|
||||
version = "1.55.0"
|
||||
version = "1.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ef5b73a927ed80b44096f8c20fb4abae65469af15198367e179ae267256e9d"
|
||||
checksum = "07835598e52dd354368429cb2abf447ce523ea446d0a533a63cb42cd0d2d9280"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
@@ -1359,9 +1359,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.1"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362"
|
||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@@ -2011,9 +2011,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
@@ -2264,7 +2264,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"url",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"xz2",
|
||||
"zstd",
|
||||
]
|
||||
@@ -2364,7 +2364,7 @@ dependencies = [
|
||||
"regex",
|
||||
"sha2 0.10.8",
|
||||
"unicode-segmentation",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2531,7 +2531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2826,7 +2826,7 @@ dependencies = [
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5382,7 +5382,7 @@ dependencies = [
|
||||
"sha2 0.10.8",
|
||||
"subprocess",
|
||||
"thiserror 1.0.69",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
@@ -6297,7 +6297,7 @@ dependencies = [
|
||||
"postgres-protocol",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7123,7 +7123,7 @@ dependencies = [
|
||||
"rkyv_derive",
|
||||
"seahash",
|
||||
"tinyvec",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7270,9 +7270,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.43"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"errno",
|
||||
@@ -7514,7 +7514,7 @@ dependencies = [
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"url",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7552,7 +7552,7 @@ dependencies = [
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8286,7 +8286,7 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
@@ -8370,7 +8370,7 @@ dependencies = [
|
||||
"stringprep",
|
||||
"thiserror 2.0.11",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
@@ -8411,7 +8411,7 @@ dependencies = [
|
||||
"stringprep",
|
||||
"thiserror 2.0.11",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
@@ -8437,7 +8437,7 @@ dependencies = [
|
||||
"sqlx-core",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9084,7 +9084,7 @@ dependencies = [
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -9314,7 +9314,7 @@ dependencies = [
|
||||
"tokio-rustls 0.24.1",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10125,7 +10125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f294bff79170ed1c5633812aff1e565c35d993a36e757f9bc0accf5eec4e6045"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
@@ -10407,9 +10407,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.12.0"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
|
||||
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"serde",
|
||||
@@ -10724,7 +10724,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -10752,7 +10752,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-api",
|
||||
"windmill-api-client",
|
||||
"windmill-autoscaling",
|
||||
@@ -10765,7 +10765,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -10840,7 +10840,7 @@ dependencies = [
|
||||
"ulid",
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-audit",
|
||||
"windmill-common",
|
||||
"windmill-git-sync",
|
||||
@@ -10852,7 +10852,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@@ -10865,12 +10865,12 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 1.0.109",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
@@ -10883,21 +10883,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-autoscaling"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-common",
|
||||
"windmill-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@@ -10950,27 +10950,27 @@ dependencies = [
|
||||
"tracing-loki",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-git-sync"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-common",
|
||||
"windmill-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-indexer"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -10987,13 +10987,13 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-tar",
|
||||
"tracing",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-macros"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
@@ -11005,7 +11005,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"convert_case 0.6.0",
|
||||
"serde",
|
||||
@@ -11014,7 +11014,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -11026,7 +11026,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-csharp"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -11038,7 +11038,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"gosyn",
|
||||
@@ -11050,7 +11050,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-graphql"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -11062,7 +11062,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-php"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -11073,7 +11073,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -11084,7 +11084,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py-imports"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -11102,7 +11102,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-rust"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"convert_case 0.6.0",
|
||||
@@ -11119,7 +11119,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-sql"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -11131,7 +11131,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -11149,7 +11149,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-wasm"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"getrandom 0.2.15",
|
||||
@@ -11171,7 +11171,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-yaml"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -11181,7 +11181,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -11208,14 +11208,14 @@ dependencies = [
|
||||
"tokio",
|
||||
"tracing",
|
||||
"ulid",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-audit",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-sql-datatype-parser-wasm"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
@@ -11225,7 +11225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -11282,7 +11282,7 @@ dependencies = [
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"urlencoding",
|
||||
"uuid 1.12.0",
|
||||
"uuid 1.12.1",
|
||||
"windmill-audit",
|
||||
"windmill-common",
|
||||
"windmill-git-sync",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -30,7 +30,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.447.6
|
||||
version: 1.448.0
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
|
||||
@@ -512,16 +512,43 @@ pub fn get_vcpus() -> Option<i64> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_memory() -> Option<i64> {
|
||||
if Path::new("/sys/fs/cgroup/memory/memory.limit_in_bytes").exists() {
|
||||
// cgroup v1
|
||||
parse_file("/sys/fs/cgroup/memory/memory.limit_in_bytes")
|
||||
} else {
|
||||
// cgroup v2
|
||||
let cgroup_path = get_cgroupv2_path()?;
|
||||
let memory_max_path = format!("{cgroup_path}/memory.max");
|
||||
fn get_memory_from_meminfo() -> Option<i64> {
|
||||
let memory_info = parse_file::<String>("/proc/meminfo")?;
|
||||
if memory_info.contains("MemTotal") {
|
||||
let memory_total = memory_info
|
||||
.split("MemTotal:")
|
||||
.nth(1)?
|
||||
.split("kB")
|
||||
.next()?
|
||||
.trim()
|
||||
.parse::<i64>()
|
||||
.ok()?;
|
||||
return Some(memory_total * 1024);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
parse_file(&memory_max_path)
|
||||
pub fn get_memory() -> Option<i64> {
|
||||
let memory_limit: Option<i64> =
|
||||
if Path::new("/sys/fs/cgroup/memory/memory.limit_in_bytes").exists() {
|
||||
// cgroup v1
|
||||
parse_file("/sys/fs/cgroup/memory/memory.limit_in_bytes")
|
||||
} else {
|
||||
// cgroup v2
|
||||
let cgroup_path = get_cgroupv2_path()?;
|
||||
let memory_max_path = format!("{cgroup_path}/memory.max");
|
||||
|
||||
parse_file(&memory_max_path)
|
||||
};
|
||||
|
||||
// if memory_max is super high, read machine total memory (meminfo)
|
||||
if memory_limit
|
||||
.as_ref()
|
||||
.is_some_and(|x| x > &(1024 * 1024 * 1024 * 1024 * 1024))
|
||||
{
|
||||
get_memory_from_meminfo()
|
||||
} else {
|
||||
memory_limit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,12 @@ mount {
|
||||
mandatory: false
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "{JOB_DIR}/bun.lock"
|
||||
dst: "/tmp/{LANG}/bun.lock"
|
||||
is_bind: true
|
||||
mandatory: false
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "{JOB_DIR}/wrapper.mjs"
|
||||
|
||||
@@ -62,24 +62,37 @@ const RELATIVE_BUN_BUILDER: &str = include_str!("../loader_builder.bun.js");
|
||||
|
||||
const NSJAIL_CONFIG_RUN_BUN_CONTENT: &str = include_str!("../nsjail/run.bun.config.proto");
|
||||
|
||||
pub const BUN_LOCK_SPLIT: &str = "\n//bun.lock\n";
|
||||
pub const BUN_LOCKB_SPLIT: &str = "\n//bun.lockb\n";
|
||||
pub const BUN_LOCK_SPLIT_WINDOWS: &str = "\r\n//bun.lock\r\n";
|
||||
pub const BUN_LOCKB_SPLIT_WINDOWS: &str = "\r\n//bun.lockb\r\n";
|
||||
|
||||
pub const EMPTY_FILE: &str = "<empty>";
|
||||
|
||||
fn split_lockfile(lockfile: &str) -> (&str, Option<&str>, bool) {
|
||||
if let Some(index) = lockfile.find(BUN_LOCKB_SPLIT) {
|
||||
/// Returns (package.json, bun.lock(b), is_empty, is_binary)
|
||||
fn split_lockfile(lockfile: &str) -> (&str, Option<&str>, bool, bool) {
|
||||
if let Some(index) = lockfile.find(BUN_LOCK_SPLIT) {
|
||||
// Split using "\n//bun.lock\n"
|
||||
let (before, after_with_sep) = lockfile.split_at(index);
|
||||
let after = &after_with_sep[BUN_LOCK_SPLIT.len()..];
|
||||
(before, Some(after), after == EMPTY_FILE, false)
|
||||
} else if let Some(index) = lockfile.find(BUN_LOCKB_SPLIT) {
|
||||
// Split using "\n//bun.lockb\n"
|
||||
let (before, after_with_sep) = lockfile.split_at(index);
|
||||
let after = &after_with_sep[BUN_LOCKB_SPLIT.len()..];
|
||||
(before, Some(after), after == EMPTY_FILE)
|
||||
(before, Some(after), after == EMPTY_FILE, true)
|
||||
} else if let Some(index) = lockfile.find(BUN_LOCK_SPLIT_WINDOWS) {
|
||||
// Split using "\r\n//bun.lock\r\n"
|
||||
let (before, after_with_sep) = lockfile.split_at(index);
|
||||
let after = &after_with_sep[BUN_LOCK_SPLIT_WINDOWS.len()..];
|
||||
(before, Some(after), after == EMPTY_FILE, false)
|
||||
} else if let Some(index) = lockfile.find(BUN_LOCKB_SPLIT_WINDOWS) {
|
||||
// Split using "\r\n//bun.lockb\r\n"
|
||||
let (before, after_with_sep) = lockfile.split_at(index);
|
||||
let after = &after_with_sep[BUN_LOCKB_SPLIT_WINDOWS.len()..];
|
||||
(before, Some(after), after == EMPTY_FILE)
|
||||
(before, Some(after), after == EMPTY_FILE, true)
|
||||
} else {
|
||||
(lockfile, None, false)
|
||||
(lockfile, None, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,18 +212,18 @@ pub async fn gen_bun_lockfile(
|
||||
}
|
||||
if !npm_mode {
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
content.push_str(BUN_LOCKB_SPLIT);
|
||||
content.push_str(BUN_LOCK_SPLIT);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
content.push_str(BUN_LOCKB_SPLIT_WINDOWS);
|
||||
content.push_str(BUN_LOCK_SPLIT_WINDOWS);
|
||||
|
||||
{
|
||||
let file = format!("{job_dir}/bun.lockb");
|
||||
let file = format!("{job_dir}/bun.lock");
|
||||
if !empty_deps && tokio::fs::metadata(&file).await.is_ok() {
|
||||
let mut file = File::open(&file).await?;
|
||||
let mut buf = vec![];
|
||||
file.read_to_end(&mut buf).await?;
|
||||
content.push_str(&base64::engine::general_purpose::STANDARD.encode(&buf));
|
||||
let mut buf = String::default();
|
||||
file.read_to_string(&mut buf).await?;
|
||||
content.push_str(&buf);
|
||||
} else {
|
||||
content.push_str(&EMPTY_FILE);
|
||||
}
|
||||
@@ -277,7 +290,7 @@ pub async fn install_bun_lockfile(
|
||||
.env_clear()
|
||||
.envs(PROXY_ENVS.clone())
|
||||
.envs(common_bun_proc_envs)
|
||||
.args(vec!["install"])
|
||||
.args(vec!["install", "--save-text-lockfile"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
|
||||
@@ -785,26 +798,30 @@ async fn compute_bundle_local_and_remote_path(
|
||||
}
|
||||
|
||||
pub async fn prepare_job_dir(reqs: &str, job_dir: &str) -> Result<()> {
|
||||
let (pkg, lock, empty) = split_lockfile(reqs);
|
||||
let (pkg, lock, empty, is_binary) = split_lockfile(reqs);
|
||||
let _ = write_file(job_dir, "package.json", pkg)?;
|
||||
|
||||
if !empty {
|
||||
if let Some(lock) = lock {
|
||||
let _ = write_lockb(lock, job_dir).await?;
|
||||
let _ = write_lock(lock, job_dir, is_binary).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn write_lockb(splitted_lockb_2: &str, job_dir: &str) -> Result<()> {
|
||||
write_file_binary(
|
||||
job_dir,
|
||||
"bun.lockb",
|
||||
&base64::engine::general_purpose::STANDARD
|
||||
.decode(splitted_lockb_2)
|
||||
.map_err(|_| error::Error::InternalErr("Could not decode bun.lockb".to_string()))?,
|
||||
)
|
||||
.await?;
|
||||
async fn write_lock(splitted_lockb_2: &str, job_dir: &str, is_binary: bool) -> Result<()> {
|
||||
if is_binary {
|
||||
write_file_binary(
|
||||
job_dir,
|
||||
"bun.lockb",
|
||||
&base64::engine::general_purpose::STANDARD
|
||||
.decode(splitted_lockb_2)
|
||||
.map_err(|_| error::Error::InternalErr(format!("Could not decode bun.lockb")))?,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
write_file(job_dir, "bun.lock", splitted_lockb_2)?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -900,26 +917,26 @@ pub async fn handle_bun_job(
|
||||
} else if let Some(codebase) = codebase.as_ref() {
|
||||
pull_codebase(&job.workspace_id, codebase, job_dir).await?;
|
||||
} else if let Some(reqs) = requirements_o.as_ref() {
|
||||
let (pkg, lock, empty) = split_lockfile(reqs);
|
||||
let (pkg, lock, empty, is_binary) = split_lockfile(reqs);
|
||||
|
||||
if lock.is_none() && !annotation.npm {
|
||||
return Err(error::Error::ExecutionErr(
|
||||
format!("Invalid requirements, expected to find //bun.lockb split pattern in reqs. Found: |{reqs}|")
|
||||
format!("Invalid requirements, expected to find //bun.lock{} split pattern in reqs. Found: |{reqs}|", if is_binary {"b"} else {""})
|
||||
));
|
||||
}
|
||||
|
||||
let _ = write_file(job_dir, "package.json", pkg)?;
|
||||
let lockb = if annotation.npm { "" } else { lock.unwrap() };
|
||||
let lock = if annotation.npm { "" } else { lock.unwrap() };
|
||||
if !empty {
|
||||
let mut skip_install = false;
|
||||
let mut create_buntar = false;
|
||||
let mut buntar_path = "".to_string();
|
||||
|
||||
if !annotation.npm {
|
||||
let _ = write_lockb(lockb, job_dir).await?;
|
||||
let _ = write_lock(lock, job_dir, is_binary).await?;
|
||||
|
||||
let mut sha_path = sha2::Sha256::new();
|
||||
sha_path.update(lockb.as_bytes());
|
||||
sha_path.update(lock.as_bytes());
|
||||
|
||||
let buntar_name =
|
||||
base64::engine::general_purpose::URL_SAFE.encode(sha_path.finalize());
|
||||
@@ -962,7 +979,7 @@ pub async fn handle_bun_job(
|
||||
Some(&vec![
|
||||
"main.ts".to_string(),
|
||||
"package.json".to_string(),
|
||||
"bun.lockb".to_string(),
|
||||
if is_binary { "bun.lockb" } else { "bun.lock" }.to_string(),
|
||||
"shared".to_string(),
|
||||
"bunfig.toml".to_string(),
|
||||
]),
|
||||
@@ -1592,25 +1609,29 @@ pub async fn start_worker(
|
||||
if let Some(codebase) = codebase.as_ref() {
|
||||
pull_codebase(w_id, codebase, job_dir).await?;
|
||||
} else if let Some(reqs) = requirements_o {
|
||||
let (pkg, lock, empty) = split_lockfile(&reqs);
|
||||
let (pkg, lock, empty, is_binary) = split_lockfile(&reqs);
|
||||
if lock.is_none() {
|
||||
return Err(error::Error::ExecutionErr(
|
||||
format!("Invalid requirements, expected to find //bun.lockb split pattern in reqs. Found: |{reqs}|")
|
||||
));
|
||||
}
|
||||
let _ = write_file(job_dir, "package.json", pkg)?;
|
||||
let lockb = lock.unwrap();
|
||||
let lock = lock.unwrap();
|
||||
if !empty {
|
||||
let _ = write_file_binary(
|
||||
job_dir,
|
||||
"bun.lockb",
|
||||
&base64::engine::general_purpose::STANDARD
|
||||
.decode(lockb)
|
||||
.map_err(|_| {
|
||||
error::Error::InternalErr("Could not decode bun.lockb".to_string())
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
if is_binary {
|
||||
let _ = write_file_binary(
|
||||
job_dir,
|
||||
"bun.lockb",
|
||||
&base64::engine::general_purpose::STANDARD
|
||||
.decode(lock)
|
||||
.map_err(|_| {
|
||||
error::Error::InternalErr("Could not decode bun.lockb".to_string())
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
write_file(job_dir, "bun.lock", lock)?;
|
||||
}
|
||||
|
||||
install_bun_lockfile(
|
||||
&mut mem_peak,
|
||||
|
||||
+1
-1
@@ -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.447.6";
|
||||
export const VERSION = "v1.448.0";
|
||||
|
||||
export async function login(email: string, password: string): Promise<string> {
|
||||
return await windmill.UserService.login({
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ export {
|
||||
// }
|
||||
// });
|
||||
|
||||
export const VERSION = "1.447.6";
|
||||
export const VERSION = "1.448.0";
|
||||
|
||||
const command = new Command()
|
||||
.name("wmill")
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.447.6",
|
||||
"version": "1.448.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill-components",
|
||||
"version": "1.447.6",
|
||||
"version": "1.448.0",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.32.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill-components",
|
||||
"version": "1.447.6",
|
||||
"version": "1.448.0",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,6 @@
|
||||
import PropertyEditor from './schema/PropertyEditor.svelte'
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte'
|
||||
import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import Label from './Label.svelte'
|
||||
@@ -23,6 +22,7 @@
|
||||
import SchemaFormDnd from './schema/SchemaFormDND.svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { tweened } from 'svelte/motion'
|
||||
import type { SchemaDiff } from '$lib/components/schema/schemaUtils'
|
||||
|
||||
export let schema: Schema | any
|
||||
export let schemaSkippedValues: string[] = []
|
||||
@@ -49,6 +49,9 @@
|
||||
export let previewSchema: Record<string, any> | undefined = undefined
|
||||
export let editPanelInitialSize: number | undefined = undefined
|
||||
export let editPanelSize = 0
|
||||
export let diff: Record<string, SchemaDiff> = {}
|
||||
export let disableDnd: boolean = false
|
||||
export let shouldDispatchChanges: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -232,6 +235,11 @@
|
||||
|
||||
let pannelButtonWidth: number = 0
|
||||
export let pannelExtraButtonWidth: number = 0
|
||||
|
||||
export function updateJson() {
|
||||
schemaString = JSON.stringify(schema, null, '\t')
|
||||
editor?.setCode(schemaString)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full h-full">
|
||||
@@ -247,37 +255,60 @@
|
||||
<Splitpanes class="splitter-hidden w-full">
|
||||
{#if !noPreview}
|
||||
<Pane bind:size={inputPanelSize} minSize={20}>
|
||||
<div class="flex flex-col pr-2 gap-2">
|
||||
<div
|
||||
class="h-full flex flex-col gap-2 {$$slots.openEditTab && editPanelSize > 0
|
||||
? 'pr-[38px]'
|
||||
: 'pr-2'}"
|
||||
>
|
||||
{#if $$slots.addProperty}
|
||||
<div class="w-full justify-left pr-2">
|
||||
<div style={`width: calc(100% - ${pannelButtonWidth - pannelExtraButtonWidth}px);`}>
|
||||
<div class="w-full justify-left pr-2 grow-0">
|
||||
<div
|
||||
style={editPanelSize > 0
|
||||
? `width: 100%;`
|
||||
: `width: calc(100% - ${pannelButtonWidth - pannelExtraButtonWidth}px);`}
|
||||
>
|
||||
<slot name="addProperty" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<SchemaFormDnd
|
||||
schema={previewSchema ? previewSchema : schema}
|
||||
{dndType}
|
||||
bind:args
|
||||
on:click={(e) => {
|
||||
opened = e.detail
|
||||
}}
|
||||
on:reorder={(e) => {
|
||||
schema.order = e.detail
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
on:change={() => {
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
{lightweightMode}
|
||||
prettifyHeader={isAppInput}
|
||||
disabled={!!previewSchema}
|
||||
/>
|
||||
<div
|
||||
class="min-h-0 overflow-y-auto grow rounded-md {$$slots.runButton
|
||||
? 'flex flex-col gap-2'
|
||||
: ''}"
|
||||
>
|
||||
<SchemaFormDnd
|
||||
nestedClasses={'flex flex-col gap-1'}
|
||||
schema={previewSchema ? previewSchema : schema}
|
||||
{dndType}
|
||||
{disableDnd}
|
||||
bind:args
|
||||
on:click={(e) => {
|
||||
opened = e.detail
|
||||
}}
|
||||
on:reorder={(e) => {
|
||||
schema.order = e.detail
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
on:change={() => {
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
{lightweightMode}
|
||||
prettifyHeader={isAppInput}
|
||||
disabled={!!previewSchema}
|
||||
{diff}
|
||||
on:acceptChange
|
||||
on:rejectChange
|
||||
on:nestedChange={() => {
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
{shouldDispatchChanges}
|
||||
/>
|
||||
|
||||
<slot name="runButton" />
|
||||
<slot name="runButton" />
|
||||
</div>
|
||||
</div>
|
||||
</Pane>
|
||||
{/if}
|
||||
@@ -425,7 +456,6 @@
|
||||
{isAppInput}
|
||||
on:change={() => {
|
||||
schema = schema
|
||||
// console.log('schema', schema)
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
>
|
||||
@@ -440,8 +470,6 @@
|
||||
const isS3 = e.detail == 'S3'
|
||||
const isOneOf = e.detail == 'oneOf'
|
||||
|
||||
selected = e.detail
|
||||
|
||||
const emptyProperty = {
|
||||
contentEncoding: undefined,
|
||||
enum_: undefined,
|
||||
@@ -508,8 +536,12 @@
|
||||
type: e.detail
|
||||
}
|
||||
}
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
// No better solution than this, needs future rework
|
||||
setTimeout(() => {
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
}, 100)
|
||||
dispatch('schemaChange')
|
||||
}}
|
||||
>
|
||||
{#each [['String', 'string'], ['Number', 'number'], ['Integer', 'integer'], ['Object', 'object'], ['OneOf', 'oneOf'], ['Array', 'array'], ['Boolean', 'boolean'], ['S3 Object', 'S3']] as x}
|
||||
@@ -558,6 +590,7 @@
|
||||
on:schemaChange={(e) => {
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
dispatch('schemaChange')
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
error = e
|
||||
}
|
||||
}
|
||||
loadSchema()
|
||||
$: $flowStore && $flowStateStore && loadSchema()
|
||||
|
||||
function handleClick() {
|
||||
selected = !selected
|
||||
@@ -51,6 +51,8 @@
|
||||
if (event.key === 'Escape' && selected) {
|
||||
selected = false
|
||||
dispatch('select', undefined)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
let jobProgressReset: () => void
|
||||
|
||||
export function test() {
|
||||
renderCount++
|
||||
runPreview($previewArgs, undefined)
|
||||
}
|
||||
|
||||
@@ -159,53 +160,53 @@
|
||||
on:close={captureLibraryDrawer?.toggleDrawer}
|
||||
>
|
||||
<div class="h-full flex flex-col gap-2">
|
||||
<CapturesInputs
|
||||
flowPath={$pathStore}
|
||||
headless={false}
|
||||
addButton={true}
|
||||
on:select={(e) => {
|
||||
selectedCapture = e.detail
|
||||
}}
|
||||
on:openTriggers={(e) => {
|
||||
dispatch('openTriggers', e.detail)
|
||||
captureLibraryDrawer?.closeDrawer()
|
||||
}}
|
||||
/>
|
||||
<div class="min-h-0 grow h-full">
|
||||
<CapturesInputs
|
||||
flowPath={$pathStore}
|
||||
headless={false}
|
||||
addButton={true}
|
||||
on:select={(e) => {
|
||||
selectedCapture = e.detail
|
||||
}}
|
||||
on:openTriggers={(e) => {
|
||||
dispatch('openTriggers', e.detail)
|
||||
captureLibraryDrawer?.closeDrawer()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="h-full overflow-hidden min-h-0 flex flex-col justify-between">
|
||||
<div class="w-full flex flex-col min-h-0 gap-2 px-2 py-2 grow">
|
||||
<div class="w-full flex flex-col">
|
||||
<Button
|
||||
color="blue"
|
||||
btnClasses="w-full"
|
||||
size="sm"
|
||||
spacingSize="xl"
|
||||
on:click={async () => {
|
||||
$previewArgs = JSON.parse(JSON.stringify(selectedCapture))
|
||||
captureLibraryDrawer?.closeDrawer()
|
||||
renderCount++
|
||||
}}
|
||||
disabled={!selectedCapture}
|
||||
<div class="w-full flex flex-col gap-2 px-2 py-2 h-[50%]">
|
||||
<div class="w-full flex flex-col">
|
||||
<Button
|
||||
color="blue"
|
||||
btnClasses="w-full"
|
||||
size="sm"
|
||||
spacingSize="xl"
|
||||
on:click={async () => {
|
||||
$previewArgs = JSON.parse(JSON.stringify(selectedCapture))
|
||||
captureLibraryDrawer?.closeDrawer()
|
||||
renderCount++
|
||||
}}
|
||||
disabled={!selectedCapture}
|
||||
>
|
||||
<ArrowLeftIcon class="w-4 h-4 mr-2" />
|
||||
Use input
|
||||
</Button>
|
||||
</div>
|
||||
<div class="w-full min-h-0 grow overflow-auto">
|
||||
{#if typeof selectedCapture == 'string' && selectedCapture == 'WINDMILL_TOO_BIG'}
|
||||
<div class="text-secondary mt-2">
|
||||
Payload too big to preview but can still be loaded</div
|
||||
>
|
||||
<ArrowLeftIcon class="w-4 h-4 mr-2" />
|
||||
Use input
|
||||
</Button>
|
||||
</div>
|
||||
<div class="w-full min-h-0 grow overflow-auto">
|
||||
{#if typeof selectedCapture == 'string' && selectedCapture == 'WINDMILL_TOO_BIG'}
|
||||
<div class="text-secondary mt-2">
|
||||
Payload too big to preview but can still be loaded</div
|
||||
>
|
||||
{:else if Object.keys(selectedCapture || {}).length > 0}
|
||||
<div class=" overflow-auto h-full p-2">
|
||||
<ObjectViewer json={selectedCapture} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center text-tertiary">
|
||||
Select an Input to preview scripts arguments
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if Object.keys(selectedCapture || {}).length > 0}
|
||||
<div class=" overflow-auto h-full p-2">
|
||||
<ObjectViewer json={selectedCapture} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center text-tertiary">
|
||||
Select an Input to preview scripts arguments
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -102,6 +102,8 @@
|
||||
if (event.key === 'Escape' && selected) {
|
||||
selected = undefined
|
||||
dispatch('select', undefined)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,16 +119,22 @@
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape' && isEditing) {
|
||||
setEditing(null)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'Escape' && selectedInput) {
|
||||
selectedInput = null
|
||||
selectedArgs = undefined
|
||||
dispatch('select', undefined)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
if (event.key === 'Enter' && isEditing) {
|
||||
updateInput(isEditing).then(() => {
|
||||
setEditing(null)
|
||||
})
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import LightweightArgInput from './LightweightArgInput.svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { dragHandleZone, type Options as DndOptions } from '@windmill-labs/svelte-dnd-action'
|
||||
import type { SchemaDiff } from '$lib/components/schema/schemaUtils'
|
||||
|
||||
export let schema: Schema | any
|
||||
export let schemaSkippedValues: string[] = []
|
||||
@@ -46,6 +47,10 @@
|
||||
| { type: 'hash'; hash: string }
|
||||
| undefined = undefined
|
||||
export let lightHeader = false
|
||||
export let diff: Record<string, SchemaDiff> = {}
|
||||
export let nestedParent: { label: string; nestedParent: any | undefined } | undefined = undefined
|
||||
export let shouldDispatchChanges = false
|
||||
export let nestedClasses = ''
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -166,7 +171,9 @@
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="w-full {$$props.class} {flexWrap ? 'flex flex-row flex-wrap gap-x-6 ' : ''}"
|
||||
class="w-full {$$props.class} {flexWrap
|
||||
? 'flex flex-row flex-wrap gap-x-6 '
|
||||
: ''} {nestedClasses}"
|
||||
use:dragHandleZone={dndConfig ?? { items: [], dragDisabled: true }}
|
||||
on:finalize
|
||||
on:consider
|
||||
@@ -174,12 +181,61 @@
|
||||
{#if keys.length > 0}
|
||||
{#each fields as item, i (item.id)}
|
||||
{@const argName = item.value}
|
||||
<div>
|
||||
<div
|
||||
class={typeof diff[argName] === 'object' && diff[argName].diff !== 'same'
|
||||
? 'bg-red-300 dark:bg-red-800 rounded-md'
|
||||
: ''}
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
{#if !schemaSkippedValues.includes(argName) && keys.includes(argName)}
|
||||
{#if typeof diff[argName] === 'object' && diff[argName].oldSchema}
|
||||
{@const formerProperty = diff[argName].oldSchema}
|
||||
<ArgInput
|
||||
{disablePortal}
|
||||
{resourceTypes}
|
||||
{prettifyHeader}
|
||||
autofocus={i == 0 && autofocus ? true : null}
|
||||
label={argName}
|
||||
description={formerProperty?.description}
|
||||
value={args[argName]}
|
||||
type={formerProperty?.type}
|
||||
oneOf={formerProperty?.oneOf}
|
||||
required={formerProperty?.required}
|
||||
pattern={formerProperty?.pattern}
|
||||
valid={inputCheck[argName]}
|
||||
defaultValue={structuredClone(formerProperty?.default)}
|
||||
enum_={formerProperty?.enum}
|
||||
format={formerProperty?.format}
|
||||
contentEncoding={formerProperty?.contentEncoding}
|
||||
customErrorMessage={formerProperty?.customErrorMessage}
|
||||
properties={formerProperty?.properties}
|
||||
order={formerProperty?.order}
|
||||
nestedRequired={formerProperty?.required}
|
||||
itemsType={formerProperty?.items}
|
||||
disabled={disabledArgs.includes(argName) || disabled || formerProperty?.disabled}
|
||||
{compact}
|
||||
{variableEditor}
|
||||
{itemPicker}
|
||||
{pickForField}
|
||||
password={linkedSecret == argName}
|
||||
extra={formerProperty}
|
||||
{showSchemaExplorer}
|
||||
simpleTooltip={schemaFieldTooltip[argName]}
|
||||
{onlyMaskPassword}
|
||||
nullable={formerProperty?.nullable}
|
||||
title={formerProperty?.title}
|
||||
placeholder={formerProperty?.placeholder}
|
||||
orderEditable={dndConfig != undefined}
|
||||
otherArgs={args}
|
||||
{helperScript}
|
||||
{lightHeader}
|
||||
hideNested={typeof diff[argName].diff === 'object'}
|
||||
diffStatus={undefined}
|
||||
/>
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="flex flex-row items-center bg-surface"
|
||||
class="flex flex-row items-center"
|
||||
on:click={() => {
|
||||
dispatch('click', argName)
|
||||
}}
|
||||
@@ -244,7 +300,14 @@
|
||||
</LightweightArgInput>
|
||||
{:else}
|
||||
<ArgInput
|
||||
on:change={() => dispatch('change')}
|
||||
on:change={() => {
|
||||
dispatch('change')
|
||||
}}
|
||||
on:nestedChange={() => {
|
||||
dispatch('nestedChange')
|
||||
}}
|
||||
on:acceptChange={(e) => dispatch('acceptChange', e.detail)}
|
||||
on:rejectChange={(e) => dispatch('rejectChange', e.detail)}
|
||||
{disablePortal}
|
||||
{resourceTypes}
|
||||
{prettifyHeader}
|
||||
@@ -285,6 +348,10 @@
|
||||
otherArgs={args}
|
||||
{helperScript}
|
||||
{lightHeader}
|
||||
diffStatus={diff[argName] ?? undefined}
|
||||
{nestedParent}
|
||||
{shouldDispatchChanges}
|
||||
{nestedClasses}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
<slot name="actions" />
|
||||
|
||||
@@ -116,7 +116,10 @@
|
||||
|
||||
let placeholderVisible = false
|
||||
function updatePlaceholderVisibility(value: string) {
|
||||
if (!value) return
|
||||
if (!value) {
|
||||
placeholderVisible = true
|
||||
return
|
||||
}
|
||||
placeholderVisible = value.trim() === ''
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import { ButtonType } from '$lib/components/common/button/model'
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, tick } from 'svelte'
|
||||
import FlowCard from '../common/FlowCard.svelte'
|
||||
import type { FlowEditorContext } from '../types'
|
||||
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
|
||||
@@ -18,21 +18,30 @@
|
||||
CornerDownLeft,
|
||||
Pen,
|
||||
ChevronRight,
|
||||
ChevronDown,
|
||||
Plus,
|
||||
History,
|
||||
Braces,
|
||||
Code,
|
||||
Save,
|
||||
X
|
||||
X,
|
||||
Check
|
||||
} from 'lucide-svelte'
|
||||
import CaptureIcon from '$lib/components/triggers/CaptureIcon.svelte'
|
||||
import FlowPreviewContent from '$lib/components/FlowPreviewContent.svelte'
|
||||
import FlowInputEditor from './FlowInputEditor.svelte'
|
||||
import CapturesInputs from '$lib/components/CapturesInputs.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ButtonDropDown from '$lib/components/meltComponents/ButtonDropDown.svelte'
|
||||
import CaptureButton from '$lib/components/triggers/CaptureButton.svelte'
|
||||
import {
|
||||
type SchemaDiff,
|
||||
getFullPath,
|
||||
setNestedProperty,
|
||||
getNestedProperty,
|
||||
schemaFromDiff,
|
||||
computeDiff,
|
||||
applyDiff
|
||||
} from '$lib/components/schema/schemaUtils'
|
||||
import SideBarTab from '$lib/components/meltComponents/SideBarTab.svelte'
|
||||
|
||||
export let noEditor: boolean
|
||||
export let disabled: boolean
|
||||
@@ -45,14 +54,18 @@
|
||||
let previewSchema: Record<string, any> | undefined = undefined
|
||||
let payloadData: Record<string, any> | undefined = undefined
|
||||
let previewArguments: Record<string, any> | undefined = $previewArgs
|
||||
let editOptionsOpen = false
|
||||
let dropdownItems: Array<{
|
||||
label: string
|
||||
onClick: () => void
|
||||
disabled?: boolean
|
||||
}> = []
|
||||
|
||||
let diff: Record<string, SchemaDiff> = {}
|
||||
let editPanelSize = $flowInputEditorState?.editPanelSize ?? 0
|
||||
let selectedSchema: Record<string, any> | undefined = undefined
|
||||
let runDisabled: boolean = false
|
||||
let editableSchemaForm: EditableSchemaForm | undefined = undefined
|
||||
let savedPreviewArgs: Record<string, any> | undefined = undefined
|
||||
|
||||
function updateEditPanelSize(size: number | undefined) {
|
||||
if (!$flowInputEditorState) return
|
||||
if (!size || size === 0) {
|
||||
@@ -73,7 +86,8 @@
|
||||
disabled:
|
||||
!$flowInputEditorState?.selectedTab ||
|
||||
$flowInputEditorState?.selectedTab === 'inputEditor',
|
||||
icon: Pen
|
||||
icon: Pen,
|
||||
selected: $flowInputEditorState?.selectedTab === 'inputEditor'
|
||||
},
|
||||
{
|
||||
label: 'Trigger captures',
|
||||
@@ -81,7 +95,8 @@
|
||||
handleEditSchema('captures')
|
||||
},
|
||||
disabled: $flowInputEditorState?.selectedTab === 'captures',
|
||||
icon: CaptureIcon
|
||||
icon: CaptureIcon,
|
||||
selected: $flowInputEditorState?.selectedTab === 'captures'
|
||||
},
|
||||
{
|
||||
label: 'History',
|
||||
@@ -89,7 +104,8 @@
|
||||
handleEditSchema('history')
|
||||
},
|
||||
disabled: $flowInputEditorState?.selectedTab === 'history',
|
||||
icon: History
|
||||
icon: History,
|
||||
selected: $flowInputEditorState?.selectedTab === 'history'
|
||||
},
|
||||
{
|
||||
label: 'Json payload',
|
||||
@@ -97,14 +113,16 @@
|
||||
handleEditSchema('json')
|
||||
},
|
||||
disabled: $flowInputEditorState?.selectedTab === 'json',
|
||||
icon: Braces
|
||||
icon: Braces,
|
||||
selected: $flowInputEditorState?.selectedTab === 'json'
|
||||
},
|
||||
{
|
||||
label: "First step's inputs",
|
||||
onClick: () => {
|
||||
handleEditSchema('firstStepInputs')
|
||||
},
|
||||
icon: Code
|
||||
icon: Code,
|
||||
selected: $flowInputEditorState?.selectedTab === 'firstStepInputs'
|
||||
},
|
||||
{
|
||||
label: 'Saved inputs',
|
||||
@@ -112,9 +130,10 @@
|
||||
handleEditSchema('savedInputs')
|
||||
},
|
||||
disabled: $flowInputEditorState?.selectedTab === 'savedInputs',
|
||||
icon: Save
|
||||
icon: Save,
|
||||
selected: $flowInputEditorState?.selectedTab === 'savedInputs'
|
||||
}
|
||||
].filter((item) => !item.disabled)
|
||||
]
|
||||
}
|
||||
|
||||
function handleEditSchema(editTab?: any) {
|
||||
@@ -130,7 +149,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
function schemaFromPayload(payload: any) {
|
||||
function schemaFromPayload(payloadData: any) {
|
||||
const payload = structuredClone(payloadData)
|
||||
const parsed = JSON.parse(JSON.stringify(payload))
|
||||
|
||||
if (!parsed) {
|
||||
@@ -157,43 +177,59 @@
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
|
||||
runPreview()
|
||||
} else if (event.key === 'Enter' && previewSchema && !preventEnter) {
|
||||
applySchemaAndArgs()
|
||||
connectFirstNode()
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
function runPreview() {
|
||||
if (previewArguments) {
|
||||
$previewArgs = previewArguments
|
||||
$previewArgs = structuredClone(previewArguments)
|
||||
}
|
||||
previewOpen = true
|
||||
flowPreviewContent?.test()
|
||||
}
|
||||
|
||||
function updatePreviewSchemaAndArgs(payload: any) {
|
||||
payloadData = payload
|
||||
if (!payload) {
|
||||
payloadData = undefined
|
||||
selectedSchema = undefined
|
||||
updatePreviewArguments(undefined)
|
||||
updatePreviewSchema(undefined)
|
||||
return
|
||||
}
|
||||
payloadData = structuredClone(payload)
|
||||
selectedSchema = schemaFromPayload(payloadData)
|
||||
updatePreviewSchema(selectedSchema)
|
||||
updatePreviewArguments(payloadData)
|
||||
}
|
||||
|
||||
async function updatePreviewSchema(newSchema: Record<string, any> | undefined) {
|
||||
if (!newSchema) {
|
||||
previewSchema = undefined
|
||||
if (runDisabled) {
|
||||
await tick()
|
||||
runDisabled = false
|
||||
}
|
||||
diff = {}
|
||||
return
|
||||
}
|
||||
previewSchema = schemaFromPayload(payload)
|
||||
updatePreviewArguments(payload)
|
||||
diff = {}
|
||||
const diffSchema = computeDiff(newSchema, $flowStore.schema)
|
||||
diff = diffSchema
|
||||
previewSchema = schemaFromDiff(diffSchema, $flowStore.schema)
|
||||
runDisabled = true
|
||||
}
|
||||
|
||||
function applySchemaAndArgs() {
|
||||
if (!previewSchema) {
|
||||
return
|
||||
}
|
||||
$flowStore.schema = previewSchema
|
||||
async function applySchemaAndArgs() {
|
||||
$flowStore.schema = applyDiff($flowStore.schema, diff)
|
||||
if (previewArguments) {
|
||||
$previewArgs = previewArguments
|
||||
savedPreviewArgs = structuredClone(previewArguments)
|
||||
}
|
||||
if ($flowInputEditorState) {
|
||||
$flowInputEditorState.selectedTab = undefined
|
||||
}
|
||||
}
|
||||
|
||||
function applySchema() {
|
||||
$flowStore.schema = previewSchema
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
if ($flowInputEditorState) {
|
||||
$flowInputEditorState.selectedTab = undefined
|
||||
}
|
||||
@@ -201,41 +237,28 @@
|
||||
|
||||
function updatePreviewArguments(payloadData: Record<string, any> | undefined) {
|
||||
if (!payloadData) {
|
||||
previewArguments = $previewArgs
|
||||
previewArguments = savedPreviewArgs
|
||||
return
|
||||
}
|
||||
previewArguments = payloadData
|
||||
savedPreviewArgs = structuredClone(previewArguments)
|
||||
previewArguments = structuredClone(payloadData)
|
||||
}
|
||||
|
||||
let jsonValid = false
|
||||
function updatePayloadFromJson(jsonInput: string) {
|
||||
if (jsonInput === undefined || jsonInput === null || jsonInput.trim() === '') {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
jsonValid = false
|
||||
return
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(jsonInput)
|
||||
updatePreviewSchemaAndArgs(parsed)
|
||||
jsonValid = true
|
||||
} catch (error) {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
jsonValid = false
|
||||
}
|
||||
}
|
||||
|
||||
let tabButtonWidth = 0
|
||||
|
||||
const TAB_TITLES: Record<string, string> = {
|
||||
inputEditor: 'Input editor',
|
||||
captures: 'Captures',
|
||||
history: 'History',
|
||||
savedInputs: 'Saved inputs',
|
||||
json: 'JSON',
|
||||
firstStepInputs: 'First step',
|
||||
undefined: ''
|
||||
}
|
||||
|
||||
let connectFirstNode: () => void = () => {}
|
||||
|
||||
let init = false
|
||||
@@ -249,6 +272,54 @@
|
||||
$: $flowInputEditorState && ((dropdownItems = getDropdownItems()), initPayloadData())
|
||||
|
||||
let preventEnter = false
|
||||
|
||||
async function acceptChange(arg: { label: string; nestedParent: any | undefined }) {
|
||||
handleChange(arg, $flowStore.schema, diff, (newSchema) => {
|
||||
$flowStore.schema = newSchema
|
||||
})
|
||||
}
|
||||
|
||||
async function rejectChange(arg: { label: string; nestedParent: any | undefined }) {
|
||||
const revertDiff = computeDiff($flowStore.schema, selectedSchema)
|
||||
handleChange(arg, selectedSchema, revertDiff, (newSchema) => {
|
||||
selectedSchema = newSchema
|
||||
})
|
||||
}
|
||||
|
||||
function handleChange(
|
||||
arg: { label: string; nestedParent: any | undefined },
|
||||
currentSchema: Record<string, any> | undefined,
|
||||
diffSchema: Record<string, SchemaDiff> | undefined,
|
||||
updateCurrentSchema: (newSchema: Record<string, any> | undefined) => void
|
||||
) {
|
||||
if (!diff || !currentSchema) {
|
||||
return
|
||||
}
|
||||
|
||||
const path = getFullPath(arg)
|
||||
const parentPath = path.slice(0, -1)
|
||||
const diffStatus = getNestedProperty({ diff: diffSchema }, path, 'diff')
|
||||
const schema = getNestedProperty(currentSchema, parentPath, 'properties')
|
||||
const localDiff = {
|
||||
[arg.label]: diffStatus
|
||||
}
|
||||
const schemaUpdated = applyDiff(schema, localDiff)
|
||||
if (parentPath.length > 0) {
|
||||
setNestedProperty(currentSchema, parentPath, schemaUpdated)
|
||||
} else {
|
||||
updateCurrentSchema(schemaUpdated)
|
||||
}
|
||||
|
||||
diff = computeDiff(selectedSchema, $flowStore.schema)
|
||||
previewSchema = schemaFromDiff(diff, $flowStore.schema)
|
||||
}
|
||||
|
||||
function resetArgs() {
|
||||
if (!previewSchema) {
|
||||
previewArguments = undefined
|
||||
savedPreviewArgs = undefined
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add svelte:window to listen for keyboard events -->
|
||||
@@ -269,6 +340,7 @@
|
||||
{#if !disabled}
|
||||
<div class="py-2 px-4 h-full">
|
||||
<EditableSchemaForm
|
||||
bind:this={editableSchemaForm}
|
||||
bind:schema={$flowStore.schema}
|
||||
isFlowInput
|
||||
on:edit={(e) => {
|
||||
@@ -284,78 +356,84 @@
|
||||
bind:editPanelSize
|
||||
editPanelInitialSize={$flowInputEditorState?.editPanelSize}
|
||||
pannelExtraButtonWidth={$flowInputEditorState?.editPanelSize ? tabButtonWidth : 0}
|
||||
{diff}
|
||||
disableDnd={!!previewSchema}
|
||||
on:rejectChange={(e) => {
|
||||
rejectChange(e.detail).then(() => {
|
||||
updatePreviewSchema(selectedSchema)
|
||||
})
|
||||
}}
|
||||
on:acceptChange={(e) => {
|
||||
acceptChange(e.detail).then(() => {
|
||||
updatePreviewSchema(selectedSchema)
|
||||
})
|
||||
}}
|
||||
shouldDispatchChanges={true}
|
||||
on:change={() => {
|
||||
previewArguments = previewArguments
|
||||
if (!previewSchema) {
|
||||
savedPreviewArgs = structuredClone(previewArguments)
|
||||
}
|
||||
}}
|
||||
on:schemaChange={() => {
|
||||
resetArgs()
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="openEditTab">
|
||||
<div
|
||||
class={twMerge(
|
||||
'flex flex-row divide-x rounded-md bg-surface overflow-hidden',
|
||||
!!$flowInputEditorState?.selectedTab ? 'rounded-r-none' : '',
|
||||
ButtonType.ColorVariants.blue.divider
|
||||
)}
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
handleEditSchema()
|
||||
}}
|
||||
title={!!$flowInputEditorState?.selectedTab
|
||||
? 'Close input editor'
|
||||
: 'Open input editor'}
|
||||
class={ButtonType.ColorVariants.blue.contained}
|
||||
>
|
||||
<div class="p-2 center-center">
|
||||
<svelte:component
|
||||
this={!!$flowInputEditorState?.selectedTab ? ChevronRight : Pen}
|
||||
size={14}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<ButtonDropDown
|
||||
{dropdownItems}
|
||||
closeOnClick={true}
|
||||
bind:open={editOptionsOpen}
|
||||
placement="bottom-end"
|
||||
>
|
||||
<div
|
||||
class={twMerge(
|
||||
'p-2 center-center hover:bg-surface-hover',
|
||||
ButtonType.ColorVariants.blue.contained,
|
||||
'flex flex-row items-center rounded-br-md',
|
||||
'transition-all duration-150 ease-in-out overflow-hidden whitespace-nowrap',
|
||||
!!$flowInputEditorState?.selectedTab ? 'w-[122px] px-3' : 'w-[30px]'
|
||||
)}
|
||||
bind:clientWidth={tabButtonWidth}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-1 justify-between w-full">
|
||||
{#if !!$flowInputEditorState?.selectedTab}
|
||||
<h2 class="text-xs">{TAB_TITLES[$flowInputEditorState?.selectedTab]}</h2>
|
||||
{/if}
|
||||
<ChevronDown size={14} />
|
||||
</div>
|
||||
</div>
|
||||
</ButtonDropDown>
|
||||
<div class={twMerge('flex flex-row divide-x', ButtonType.ColorVariants.blue.divider)}>
|
||||
<SideBarTab {dropdownItems} fullMenu={!!$flowInputEditorState?.selectedTab}>
|
||||
<svelte:fragment slot="close button">
|
||||
<button
|
||||
on:click={() => {
|
||||
handleEditSchema()
|
||||
}}
|
||||
title={!!$flowInputEditorState?.selectedTab
|
||||
? 'Close input editor'
|
||||
: 'Open input editor'}
|
||||
class={twMerge(
|
||||
ButtonType.ColorVariants.blue.contained,
|
||||
!!$flowInputEditorState?.selectedTab
|
||||
? 'rounded-tl-md border-l border-t'
|
||||
: 'rounded-md border'
|
||||
)}
|
||||
>
|
||||
<div class="p-2 center-center">
|
||||
<svelte:component
|
||||
this={!!$flowInputEditorState?.selectedTab ? ChevronRight : Pen}
|
||||
size={14}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</svelte:fragment>
|
||||
</SideBarTab>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="addProperty">
|
||||
{#if !!previewSchema}
|
||||
<div
|
||||
class={twMerge(
|
||||
'bg-blue-50 border-blue-200 border dark:bg-blue-900/40 dark:border-blue-700/40 text-xs p-2 w-full flex flex-row gap-2 items-center justify-left rounded-md',
|
||||
'text-blue-700 dark:text-blue-100',
|
||||
'relative'
|
||||
)}
|
||||
>
|
||||
<span> Preview only, update schema to save.</span>
|
||||
<div class="flex flex-row items-center gap-2 absolute right-2">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="light"
|
||||
size="xs2"
|
||||
startIcon={{ icon: X }}
|
||||
shortCut={{ key: 'esc', withoutModifier: true }}
|
||||
nonCaptureEvent
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2 right-2 justify-end">
|
||||
<Button
|
||||
size="xs"
|
||||
color="green"
|
||||
disabled={!previewSchema}
|
||||
shortCut={{ Icon: CornerDownLeft, hide: false, withoutModifier: true }}
|
||||
startIcon={{ icon: Check }}
|
||||
on:click={() => {
|
||||
applySchemaAndArgs()
|
||||
connectFirstNode()
|
||||
}}
|
||||
>
|
||||
{Object.values(diff).every((el) => el.diff === 'same')
|
||||
? 'Apply args'
|
||||
: 'Update schema'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="border"
|
||||
color="light"
|
||||
size="xs"
|
||||
startIcon={{ icon: X }}
|
||||
shortCut={{ key: 'esc', withoutModifier: true }}
|
||||
nonCaptureEvent
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<AddPropertyV2
|
||||
@@ -363,6 +441,14 @@
|
||||
bind:this={addProperty}
|
||||
on:change={() => {
|
||||
$flowStore = $flowStore
|
||||
if (editableSchemaForm) {
|
||||
editableSchemaForm.updateJson()
|
||||
}
|
||||
}}
|
||||
on:addNew={(e) => {
|
||||
handleEditSchema('inputEditor')
|
||||
editableSchemaForm?.openField(e.detail)
|
||||
$flowStore = $flowStore
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
@@ -378,9 +464,7 @@
|
||||
<svelte:fragment slot="extraTab">
|
||||
{#if $flowInputEditorState?.selectedTab === 'history'}
|
||||
<FlowInputEditor
|
||||
disabled={!payloadData}
|
||||
on:applySchemaAndArgs={applySchemaAndArgs}
|
||||
on:applySchema={applySchema}
|
||||
title="History"
|
||||
on:destroy={() => {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
}}
|
||||
@@ -396,12 +480,10 @@
|
||||
</FlowInputEditor>
|
||||
{:else if $flowInputEditorState?.selectedTab === 'captures'}
|
||||
<FlowInputEditor
|
||||
disabled={!payloadData}
|
||||
on:applySchemaAndArgs={applySchemaAndArgs}
|
||||
on:applySchema={applySchema}
|
||||
on:destroy={() => {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
}}
|
||||
title="Trigger captures"
|
||||
>
|
||||
<svelete:fragment slot="action">
|
||||
<div class="center-center">
|
||||
@@ -417,13 +499,10 @@
|
||||
</FlowInputEditor>
|
||||
{:else if $flowInputEditorState?.selectedTab === 'savedInputs'}
|
||||
<FlowInputEditor
|
||||
{preventEnter}
|
||||
disabled={!payloadData}
|
||||
on:applySchemaAndArgs={applySchemaAndArgs}
|
||||
on:applySchema={applySchema}
|
||||
on:destroy={() => {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
}}
|
||||
title="Saved inputs"
|
||||
>
|
||||
<SavedInputsPicker
|
||||
flowPath={initialPath}
|
||||
@@ -438,13 +517,10 @@
|
||||
</FlowInputEditor>
|
||||
{:else if $flowInputEditorState?.selectedTab === 'json'}
|
||||
<FlowInputEditor
|
||||
{preventEnter}
|
||||
disabled={!jsonValid}
|
||||
on:applySchemaAndArgs={applySchemaAndArgs}
|
||||
on:applySchema={applySchema}
|
||||
on:destroy={() => {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
}}
|
||||
title="Json payload"
|
||||
>
|
||||
<SimpleEditor
|
||||
on:focus={() => {
|
||||
@@ -470,22 +546,25 @@
|
||||
</FlowInputEditor>
|
||||
{:else if $flowInputEditorState?.selectedTab === 'firstStepInputs'}
|
||||
<FlowInputEditor
|
||||
disabled={!previewSchema}
|
||||
on:applySchemaAndArgs={() => {
|
||||
applySchemaAndArgs()
|
||||
connectFirstNode()
|
||||
}}
|
||||
on:applySchema={applySchema}
|
||||
on:destroy={() => {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
connectFirstNode = () => {}
|
||||
}}
|
||||
title="First step's inputs"
|
||||
>
|
||||
<FirstStepInputs
|
||||
on:connectFirstNode={({ detail }) => {
|
||||
connectFirstNode = detail.connectFirstNode
|
||||
}}
|
||||
on:select={(e) => {
|
||||
previewSchema = e.detail ?? undefined
|
||||
if (e.detail) {
|
||||
const diffSchema = computeDiff(e.detail, $flowStore.schema)
|
||||
diff = diffSchema
|
||||
previewSchema = schemaFromDiff(diffSchema, $flowStore.schema)
|
||||
runDisabled = true
|
||||
} else {
|
||||
updatePreviewSchemaAndArgs(undefined)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FlowInputEditor>
|
||||
@@ -496,7 +575,7 @@
|
||||
<Button
|
||||
color="dark"
|
||||
btnClasses="w-fit"
|
||||
disabled={!!previewSchema}
|
||||
disabled={runDisabled}
|
||||
size="xs"
|
||||
shortCut={{ Icon: CornerDownLeft, hide: false }}
|
||||
on:click={() => {
|
||||
|
||||
@@ -1,51 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { CornerDownLeft, Save } from 'lucide-svelte'
|
||||
|
||||
export let name: string = ''
|
||||
export let disabled = false
|
||||
export let preventEnter = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function applySchemaAndArgs() {
|
||||
dispatch('applySchemaAndArgs')
|
||||
}
|
||||
export let title: string = ''
|
||||
|
||||
onDestroy(() => {
|
||||
dispatch('destroy')
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter' && !preventEnter) {
|
||||
applySchemaAndArgs()
|
||||
e.preventDefault()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div class="flex flex-col h-full px-3 pb-3">
|
||||
<div
|
||||
class="items-center grow-0 flex flex-row justify-between gap-2 data-schema-picker min-h-[40px]"
|
||||
>
|
||||
<h2 class="font-semibold text-secondary text-sm flex flex-row items-center gap-1 leading-6">
|
||||
{title}
|
||||
</h2>
|
||||
<slot name="action" />
|
||||
</div>
|
||||
|
||||
<div class="h-full p-2">
|
||||
<Section label={name} class="h-full" small={true}>
|
||||
<svelte:fragment slot="header">
|
||||
<slot name="header" />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="action">
|
||||
<div class="flex flex-row gap-2 data-schema-picker">
|
||||
<slot name="action" />
|
||||
<Button
|
||||
size="xs2"
|
||||
color="dark"
|
||||
{disabled}
|
||||
shortCut={{ Icon: CornerDownLeft, hide: false, withoutModifier: true }}
|
||||
startIcon={{ icon: Save }}
|
||||
on:click={applySchemaAndArgs}>Update schema</Button
|
||||
>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<div class="w-full min-h-0 grow">
|
||||
<slot />
|
||||
</Section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<script lang="ts">
|
||||
export let dropdownItems: Array<{
|
||||
label: string
|
||||
onClick: () => void
|
||||
icon?: any
|
||||
selected?: boolean
|
||||
}> = []
|
||||
|
||||
export let fullMenu: boolean = false
|
||||
|
||||
let open = false
|
||||
let timeout: NodeJS.Timeout | null = null
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (!fullMenu) return
|
||||
timeout = setTimeout(() => {
|
||||
open = true
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
timeout = null
|
||||
}
|
||||
open = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="flex flex-col relative !overflow-visible"
|
||||
on:mouseenter={handleMouseEnter}
|
||||
on:mouseleave={handleMouseLeave}
|
||||
>
|
||||
<slot name="close button" />
|
||||
|
||||
{#if fullMenu}
|
||||
<div
|
||||
class="absolute flex-col top-[30px] left-0 z-50 bg-surface border-l border-b {open
|
||||
? 'rounded-md rounded-tl-none overflow-hidden shadow-md'
|
||||
: 'rounded-bl-md'}"
|
||||
>
|
||||
{#each dropdownItems as item}
|
||||
<button
|
||||
class="hover:bg-surface-hover p-2 transition-colors duration-150 w-full {item.selected
|
||||
? 'bg-surface-selected'
|
||||
: 'text-secondary'}"
|
||||
on:click={() => {
|
||||
item.onClick()
|
||||
open = false
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2 min-h-[20px]">
|
||||
{#if item.icon}
|
||||
<svelte:component this={item.icon} size={14} />
|
||||
{/if}
|
||||
|
||||
{#if open}
|
||||
<p class="text-xs text-secondary whitespace-nowrap text-left">
|
||||
{item.label}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -138,7 +138,9 @@
|
||||
if (Object.keys(modifiedProperties).includes(argName)) {
|
||||
delete modifiedProperties[argName]
|
||||
|
||||
modifiedObject.required = schema.required.filter((arg) => arg !== argName)
|
||||
if (modifiedObject.required) {
|
||||
modifiedObject.required = schema.required.filter((arg) => arg !== argName)
|
||||
}
|
||||
if (modifiedObject.order) {
|
||||
modifiedObject.order = modifiedObject.order.filter((arg) => arg !== argName)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
} from '$lib/common'
|
||||
import { emptySchema, sendUserToast } from '$lib/utils'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import SimpleEditor from '../SimpleEditor.svelte'
|
||||
import AddPropertyFormV2 from './AddPropertyFormV2.svelte'
|
||||
export let schema: Schema | any = emptySchema()
|
||||
|
||||
@@ -24,13 +23,10 @@
|
||||
schema = emptySchema()
|
||||
}
|
||||
|
||||
let schemaString: string = ''
|
||||
|
||||
// Internal state: bound to args builder modal
|
||||
let argError = ''
|
||||
let editing = false
|
||||
let oldArgName: string | undefined // when editing argument and changing name
|
||||
let jsonEditor: SimpleEditor
|
||||
|
||||
reorder()
|
||||
|
||||
@@ -59,7 +55,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleAddOrEditArgument(modalProperty: ModalSchemaProperty): void {
|
||||
export function handleAddOrEditArgument(modalProperty: ModalSchemaProperty): void {
|
||||
// If editing the arg's name, oldName containing the old argument name must be provided
|
||||
argError = ''
|
||||
modalProperty.name = modalProperty.name.trim()
|
||||
@@ -109,8 +105,6 @@
|
||||
}
|
||||
|
||||
schema = schema
|
||||
schemaString = JSON.stringify(schema, null, '\t')
|
||||
jsonEditor?.setCode(schemaString)
|
||||
|
||||
if (argError !== '') {
|
||||
sendUserToast(argError, true)
|
||||
@@ -137,12 +131,13 @@
|
||||
if (Object.keys(modifiedProperties).includes(argName)) {
|
||||
delete modifiedProperties[argName]
|
||||
|
||||
modifiedObject.required = schema.required.filter((arg) => arg !== argName)
|
||||
if (modifiedObject.required) {
|
||||
modifiedObject.required = schema.required.filter((arg) => arg !== argName)
|
||||
}
|
||||
if (modifiedObject.order) {
|
||||
modifiedObject.order = modifiedObject.order.filter((arg) => arg !== argName)
|
||||
}
|
||||
schema = schema
|
||||
schemaString = JSON.stringify(schema, null, '\t')
|
||||
dispatch('change', schema)
|
||||
} else {
|
||||
throw Error('Argument not found!')
|
||||
@@ -163,6 +158,7 @@
|
||||
selectedType: 'string',
|
||||
name: e.detail.name
|
||||
})
|
||||
dispatch('addNew', e.detail.name)
|
||||
} catch (err) {
|
||||
sendUserToast(`Could not add argument: ${err}`, true)
|
||||
}
|
||||
|
||||
@@ -154,8 +154,11 @@
|
||||
<div class="flex flex-col w-full mt-2">
|
||||
<Label label="Nested properties">
|
||||
<svelte:self
|
||||
on:change={() => (schema = schema)}
|
||||
schema={schema.properties[item.value]}
|
||||
on:change={() => {
|
||||
schema = schema
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
bind:schema={schema.properties[item.value]}
|
||||
parentId={item.value}
|
||||
/>
|
||||
</Label>
|
||||
@@ -187,7 +190,13 @@
|
||||
editTab="inputEditor"
|
||||
>
|
||||
<svelte:fragment slot="addProperty">
|
||||
<AddPropertyV2 bind:schema on:change>
|
||||
<AddPropertyV2
|
||||
bind:schema
|
||||
on:change
|
||||
on:addNew={(e) => {
|
||||
editableSchemaForm?.openField(e.detail)
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
<div
|
||||
class="w-full py-2 flex justify-center items-center border border-dashed rounded-md hover:bg-surface-hover"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
let resourceIsTextFile: boolean = false
|
||||
let addProperty: AddPropertyV2 | undefined = undefined
|
||||
let editableSchemaForm: EditableSchemaForm | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -90,6 +91,9 @@
|
||||
bind:schema
|
||||
bind:this={addProperty}
|
||||
on:change={() => dispatch('change', schema)}
|
||||
on:addNew={(e) => {
|
||||
editableSchemaForm?.openField(e.detail)
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
<div
|
||||
@@ -101,6 +105,7 @@
|
||||
</AddPropertyV2>
|
||||
{/if}
|
||||
<EditableSchemaForm
|
||||
bind:this={editableSchemaForm}
|
||||
bind:schema
|
||||
on:change={() => dispatch('change', schema)}
|
||||
isFlowInput
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { GripVertical } from 'lucide-svelte'
|
||||
import type { Schema } from '$lib/common'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
import type { SchemaDiff } from '$lib/components/schema/schemaUtils'
|
||||
export let dndType: string | undefined = undefined
|
||||
export let schema: Schema
|
||||
export let args: Record<string, any> = {}
|
||||
@@ -15,6 +15,11 @@
|
||||
export let disablePortal: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let schemaSkippedValues: string[] = []
|
||||
export let nestedParent: { label: string; nestedParent: any | undefined } | undefined = undefined
|
||||
export let disableDnd: boolean = false
|
||||
export let shouldDispatchChanges: boolean = false
|
||||
export let diff: Record<string, SchemaDiff> = {}
|
||||
export let nestedClasses = ''
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const flipDurationMs = 200
|
||||
@@ -66,12 +71,16 @@
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<SchemaForm
|
||||
{nestedClasses}
|
||||
{schemaSkippedValues}
|
||||
on:click
|
||||
on:change
|
||||
on:reorder
|
||||
on:consider={handleConsider}
|
||||
on:finalize={handleFinalize}
|
||||
on:acceptChange
|
||||
on:rejectChange
|
||||
on:nestedChange
|
||||
{lightweightMode}
|
||||
bind:args
|
||||
{prettifyHeader}
|
||||
@@ -79,17 +88,24 @@
|
||||
{disablePortal}
|
||||
{disabled}
|
||||
bind:schema
|
||||
dndConfig={{
|
||||
items,
|
||||
flipDurationMs,
|
||||
dropTargetStyle: {},
|
||||
type: dndType ?? 'top-level'
|
||||
}}
|
||||
dndConfig={disableDnd
|
||||
? undefined
|
||||
: {
|
||||
items,
|
||||
flipDurationMs,
|
||||
dropTargetStyle: {},
|
||||
type: dndType ?? 'top-level'
|
||||
}}
|
||||
{items}
|
||||
{diff}
|
||||
{nestedParent}
|
||||
{shouldDispatchChanges}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
<div class="w-4 h-8 cursor-move ml-2 handle" aria-label="drag-handle" use:dragHandle>
|
||||
<GripVertical size={16} />
|
||||
</div>
|
||||
{#if !disableDnd}
|
||||
<div class="w-4 h-8 cursor-move ml-2 handle" aria-label="drag-handle" use:dragHandle>
|
||||
<GripVertical size={16} />
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</SchemaForm>
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
export type SchemaDiff = {
|
||||
diff: 'same' | 'added' | 'removed' | 'modified' | Record<string, SchemaDiff>
|
||||
fullSchema: { [key: string]: any } | undefined
|
||||
oldSchema?: { [key: string]: any } | undefined
|
||||
}
|
||||
|
||||
function isCompatible(diff: Record<string, SchemaDiff>) {
|
||||
let compatible = true
|
||||
Object.values(diff).forEach((diff) => {
|
||||
if (diff.diff === 'added' || diff.diff === 'modified' || diff.diff === 'removed') {
|
||||
compatible = false
|
||||
} else if (isRecordSchemaDiff(diff.diff)) {
|
||||
compatible = isCompatible(diff.diff)
|
||||
}
|
||||
})
|
||||
return compatible
|
||||
}
|
||||
|
||||
function isCompatibleObject(a: any, b: any): boolean {
|
||||
if (!a || !b) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (a.type === 'null' || b.type === 'null') {
|
||||
return true
|
||||
}
|
||||
|
||||
if (a.type !== b.type) {
|
||||
if (
|
||||
(a.type === 'number' || a.type === 'integer') &&
|
||||
(b.type === 'number' || b.type === 'integer')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
switch (a.type) {
|
||||
case 'object':
|
||||
if (a.oneOf || b.oneOf) {
|
||||
//TODO: handle oneOf compatibility. here we assume that only b is oneOf
|
||||
return true
|
||||
}
|
||||
return a.format === b.format
|
||||
|
||||
case 'array':
|
||||
return !a.items || !b.items || a.items?.type === b.items?.type
|
||||
|
||||
case 'string':
|
||||
return a.format === b.format
|
||||
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
case 'integer':
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function computeDiff(
|
||||
previewSchema: { [key: string]: any } | undefined,
|
||||
currentSchema: { [key: string]: any } | undefined
|
||||
) {
|
||||
if (!previewSchema || !currentSchema) {
|
||||
return {}
|
||||
}
|
||||
const diff: Record<string, SchemaDiff> = {}
|
||||
|
||||
if (previewSchema?.properties) {
|
||||
Object.keys(previewSchema.properties).forEach((key) => {
|
||||
if (!currentSchema?.properties?.[key]) {
|
||||
diff[key] = {
|
||||
diff: 'added',
|
||||
fullSchema: previewSchema.properties[key]
|
||||
}
|
||||
} else {
|
||||
const previewProp = previewSchema.properties[key]
|
||||
const currentProp = currentSchema.properties[key]
|
||||
if (previewProp.type === 'object' && currentProp.type === 'object') {
|
||||
if (JSON.stringify(previewProp) === JSON.stringify(currentProp)) {
|
||||
diff[key] = { diff: 'same', fullSchema: undefined }
|
||||
} else if (previewProp.oneOf || currentProp.oneOf) {
|
||||
if (isCompatibleObject(previewProp, currentProp)) {
|
||||
diff[key] = { diff: 'same', fullSchema: undefined }
|
||||
} else {
|
||||
diff[key] = { diff: 'modified', fullSchema: previewProp, oldSchema: currentProp }
|
||||
}
|
||||
} else if (previewProp.format || currentProp.format) {
|
||||
//TODO: handle s3 object compatibility
|
||||
diff[key] = { diff: 'modified', fullSchema: previewProp, oldSchema: currentProp }
|
||||
} else {
|
||||
const diffProp = computeDiff(previewProp, currentProp)
|
||||
const checkIfSame = isCompatible(diffProp)
|
||||
if (checkIfSame) {
|
||||
diff[key] = { diff: 'same', fullSchema: undefined }
|
||||
} else {
|
||||
diff[key] = {
|
||||
diff: diffProp,
|
||||
fullSchema: previewProp,
|
||||
oldSchema: currentProp
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isCompatibleObject(previewProp, currentProp)) {
|
||||
diff[key] = { diff: 'same', fullSchema: undefined }
|
||||
} else {
|
||||
diff[key] = { diff: 'modified', fullSchema: previewProp, oldSchema: currentProp }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (currentSchema?.properties) {
|
||||
Object.keys(currentSchema.properties).forEach((key) => {
|
||||
if (!previewSchema?.properties?.[key]) {
|
||||
diff[key] = { diff: 'removed', fullSchema: undefined }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
export function schemaFromDiff(
|
||||
diff: Record<string, SchemaDiff>,
|
||||
schema: { [key: string]: any } | undefined
|
||||
) {
|
||||
if (!schema) {
|
||||
return undefined
|
||||
}
|
||||
const newSchema = structuredClone(schema)
|
||||
Object.keys(diff).forEach((key) => {
|
||||
const diffValue = diff[key].diff
|
||||
if (diffValue === 'added' || diffValue === 'modified') {
|
||||
newSchema.properties[key] = diff[key].fullSchema
|
||||
if (newSchema.order && !newSchema.order.includes(key)) {
|
||||
newSchema.order.push(key)
|
||||
}
|
||||
} else if (isRecordSchemaDiff(diffValue)) {
|
||||
// Handle nested diffs
|
||||
newSchema.properties[key] = schemaFromDiff(diffValue, schema.properties[key])
|
||||
}
|
||||
})
|
||||
return newSchema
|
||||
}
|
||||
|
||||
export function getFullPath(arg: { label: string; nestedParent: any | undefined }): string[] {
|
||||
const getPath = (current: { label: string; nestedParent: any | undefined }): string[] => {
|
||||
if (!current.nestedParent) {
|
||||
return [current.label]
|
||||
}
|
||||
return [...getPath(current.nestedParent), current.label]
|
||||
}
|
||||
|
||||
return getPath(arg)
|
||||
}
|
||||
|
||||
export function getNestedProperty(obj: any, path: string[], field: string = 'properties') {
|
||||
return path.reduce((curr, key) => curr?.[field]?.[key], obj)
|
||||
}
|
||||
|
||||
export function setNestedProperty(
|
||||
obj: any,
|
||||
path: string[],
|
||||
value: any,
|
||||
field: string = 'properties'
|
||||
) {
|
||||
const pathCopy = [...path]
|
||||
const lastKey = pathCopy.pop()
|
||||
const target = pathCopy.reduce((curr, key) => {
|
||||
if (!(key in curr[field])) {
|
||||
curr[field][key] = { [field]: {} }
|
||||
}
|
||||
return curr[field][key]
|
||||
}, obj)
|
||||
if (lastKey && value) {
|
||||
const newValue = structuredClone(value)
|
||||
target[field][lastKey] = newValue
|
||||
return
|
||||
} else if (lastKey && !value) {
|
||||
delete target[field][lastKey]
|
||||
}
|
||||
}
|
||||
|
||||
function isRecordSchemaDiff(value: SchemaDiff['diff']): value is Record<string, SchemaDiff> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
|
||||
export function applyDiff(
|
||||
schema: Record<string, any> | undefined,
|
||||
diff: Record<string, SchemaDiff> | undefined
|
||||
) {
|
||||
if (!diff || !schema) {
|
||||
return
|
||||
}
|
||||
|
||||
let newSchema = structuredClone(schema)
|
||||
|
||||
Object.keys(diff).forEach((key) => {
|
||||
const diffValue = diff[key].diff
|
||||
if (diffValue === 'removed') {
|
||||
delete newSchema.properties[key]
|
||||
if (newSchema.order) {
|
||||
newSchema.order = newSchema.order.filter((x) => x !== key)
|
||||
}
|
||||
} else if (diffValue === 'added' || diffValue === 'modified' || isRecordSchemaDiff(diffValue)) {
|
||||
newSchema.properties[key] = diff[key].fullSchema
|
||||
if (newSchema.order && !newSchema.order.includes(key)) {
|
||||
newSchema.order.push(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return newSchema
|
||||
}
|
||||
@@ -133,6 +133,8 @@
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape' && selected) {
|
||||
deselect()
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +151,7 @@
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
|
||||
<Label label="Trigger captures" {headless} class="h-full flex flex-col gap-1">
|
||||
<Label label="Trigger captures" {headless} class="h-full {headless ? '' : 'flex flex-col gap-1'}">
|
||||
<svelte:fragment slot="header">
|
||||
{#if addButton}
|
||||
<div class="inline-block">
|
||||
@@ -180,7 +182,13 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<div
|
||||
class={fullHeight ? 'h-full' : capturesLength > 7 ? 'h-[300px]' : 'h-fit'}
|
||||
class={fullHeight
|
||||
? headless
|
||||
? 'h-full'
|
||||
: 'min-h-0 grow'
|
||||
: capturesLength > 7
|
||||
? 'h-[300px]'
|
||||
: 'h-fit'}
|
||||
use:clickOutside={{ capture: false, exclude: getPropPickerElements }}
|
||||
on:click_outside={() => {
|
||||
if (firstClick) {
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
wmill = ">=1.447.6"
|
||||
wmill_pg = ">=1.447.6"
|
||||
wmill = ">=1.448.0"
|
||||
wmill_pg = ">=1.448.0"
|
||||
sendgrid = "*"
|
||||
mysql-connector-python = "*"
|
||||
pymongo = "*"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.447.6
|
||||
version: 1.448.0
|
||||
title: OpenFlow Spec
|
||||
contact:
|
||||
name: Ruben Fiszel
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
RootModule = 'WindmillClient.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.447.6'
|
||||
ModuleVersion = '1.448.0'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
description = "A client library for accessing Windmill server wrapping the Windmill client API"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill-pg"
|
||||
version = "1.447.6"
|
||||
version = "1.448.0"
|
||||
description = "An extension client for the wmill client library focused on pg"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@windmill/windmill",
|
||||
"version": "1.447.6",
|
||||
"version": "1.448.0",
|
||||
"exports": "./src/index.ts",
|
||||
"publish": {
|
||||
"exclude": ["!src", "./s3Types.ts", "./client.ts"]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "windmill-client",
|
||||
"description": "Windmill SDK client for browsers and Node.js",
|
||||
"version": "1.447.6",
|
||||
"version": "1.448.0",
|
||||
"author": "Ruben Fiszel",
|
||||
"license": "Apache 2.0",
|
||||
"devDependencies": {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.447.6
|
||||
1.448.0
|
||||
|
||||
Reference in New Issue
Block a user