Compare commits

...

57 Commits

Author SHA1 Message Date
Ruben Fiszel
020e5f7b32 update metrics 2023-02-27 11:56:55 +01:00
Ruben Fiszel
1414030afe chore(main): release 1.70.1 (#1241) 2023-02-27 10:41:23 +01:00
Ruben Fiszel
92bf928b78 chore(main): release 1.70.1 (#1239)
* chore(main): release 1.70.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-27 10:41:23 +01:00
Faton Ramadani
0bcc036a84 fix(frontend): Fix inline scripts list (#1240) 2023-02-27 10:41:23 +01:00
Faton Ramadani
6277188c1b fix(frontend): Fix subgrid lock (#1232)
* fix(frontend): Fix subgrid lock

* feat(frontend): restore
2023-02-27 10:41:23 +01:00
Ruben Fiszel
65c9d43419 fix findGridItemById 2023-02-27 10:41:23 +01:00
Faton Ramadani
cc5744ee2d fix(frontend): Disable move in nested subgrid (#1238)
* fix(frontend): Disable move in nested subgrid

* fix(frontend): Disable move in nested subgrid
2023-02-27 10:41:23 +01:00
Ruben Fiszel
1e796881b3 fix(cli): make cli resilient to systems without openable browsers 2023-02-27 10:41:23 +01:00
Ruben Fiszel
a55d99a8b7 chore(main): release 1.70.0 (#1236)
* chore(main): release 1.70.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-27 10:41:23 +01:00
Ruben Fiszel
07477f9e35 fix(cli): bump cli to non broken client 1.69.3 2023-02-27 10:41:23 +01:00
Ruben Fiszel
9409d5e266 update 2023-02-27 10:41:23 +01:00
Ruben Fiszel
2d71ebbe09 fix stripe checkout 2023-02-27 10:41:23 +01:00
Ruben Fiszel
c1673ac036 update 2023-02-27 08:27:08 +01:00
Ruben Fiszel
8ca54e02c0 Merge branch 'main' into rf/diff3 2023-02-27 08:23:29 +01:00
Ruben Fiszel
cd25570003 fix minor editor bugs 2023-02-27 00:53:49 +01:00
Ruben Fiszel
e95f8ef6bf add none color for buttons 2023-02-27 00:27:20 +01:00
Ruben Fiszel
c3d1c8ac39 fix many apps bugs 2023-02-26 23:43:00 +01:00
Ruben Fiszel
d38aff2fe2 fix: app setup and sync now uses 1.69.3 2023-02-26 14:09:16 +01:00
Ruben Fiszel
95851ea486 minor app nits 2023-02-26 13:58:51 +01:00
Ruben Fiszel
b690d801d4 feat(apps): add ag grid 2023-02-25 13:11:50 +01:00
Faton Ramadani
104e4ac5e7 feat(frontend): move to other grid (#1230)
* feat(frontend): move to other grid

* feat(frontend): wip

* feat(frontend): Fix component move

* fix(frontend): Fix build

* feat(frontend): Fix moving

* fix(frontend): Simplify code
2023-02-25 11:31:12 +01:00
Faton Ramadani
e87f4fc44b fix(frontend): Fix duplication (#1237) 2023-02-25 10:18:21 +01:00
Ruben Fiszel
e1f686d850 fix(frontend): fix graph viewer id assignment 2023-02-25 08:48:24 +01:00
Ruben Fiszel
7da7dac3ac chore(main): release 1.69.3 (#1234) 2023-02-24 21:11:58 +01:00
Ruben Fiszel
c2e5afd4e0 fix(deno): fix denoify buffer handling 2023-02-24 21:09:37 +01:00
Ruben Fiszel
ad9c386f41 making slider/range values connectable 2023-02-24 20:50:01 +01:00
Ruben Fiszel
a4e3f98b7d chore(main): release 1.69.2 (#1233)
* chore(main): release 1.69.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-24 19:57:50 +01:00
Ruben Fiszel
dd28308c3c fix(app): fix all nested behavior 2023-02-24 19:52:20 +01:00
Ruben Fiszel
833c2655ea push 2023-02-24 19:52:20 +01:00
Faton Ramadani
a8295d0b5a fix(frontend): Fix findGridItem 2023-02-24 19:52:20 +01:00
Ruben Fiszel
897e2f6b53 flatten 2023-02-24 19:52:20 +01:00
Faton Ramadani
5bb77edf45 fix(frontend): Fix findGridItem 2023-02-24 19:52:20 +01:00
Faton Ramadani
8ddcf4d9c1 fix(frontend): Fix next id 2023-02-24 19:52:20 +01:00
Faton Ramadani
33ebe2da8e fix(frontend): wip 2023-02-24 19:52:20 +01:00
Ruben Fiszel
b3ee747014 pushed 2023-02-24 19:52:20 +01:00
Faton Ramadani
fa105b4cae fix(frontend): gridtab 2023-02-24 19:52:20 +01:00
Faton Ramadani
483407cdf0 fix(frontend): duplicate 2023-02-24 19:52:20 +01:00
Faton Ramadani
008c30fcaa fix(frontend): delete grid item 2023-02-24 19:52:20 +01:00
Ruben Fiszel
3387bb0d83 script editor panel 2023-02-24 19:52:20 +01:00
Ruben Fiszel
e08e7e4ae6 settings panel 2023-02-24 19:52:20 +01:00
Faton Ramadani
ea1b2c29b9 fix(frontend): rewrote utils 2023-02-24 19:52:20 +01:00
Ruben Fiszel
4ad6fbefd3 flatten 2023-02-24 19:52:20 +01:00
Ruben Fiszel
397ecd64d4 chore(main): release 1.69.1 (#1231)
* chore(main): release 1.69.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-24 17:26:53 +01:00
Ruben Fiszel
dd7e8c742c fix(deno): remove mysql support waiting for deno fix 2023-02-24 17:19:13 +01:00
Ruben Fiszel
2f78132e08 fix(deno): remove mysql support waiting for deno fix 2023-02-24 17:11:53 +01:00
Ruben Fiszel
0041411c06 subgrids editor panel iter 1 2023-02-24 14:48:28 +01:00
Ruben Fiszel
54955b710c fix subgrids final2 2023-02-24 13:11:06 +01:00
Ruben Fiszel
1eb5a0d1d3 fix subgrids final 2023-02-24 11:59:28 +01:00
Ruben Fiszel
ddda14c52b app fixes 2023-02-24 11:39:50 +01:00
Ruben Fiszel
53ddf013df foo 2023-02-24 11:01:45 +01:00
Ruben Fiszel
5123c9365c fix subgrids final 2023-02-24 07:27:22 +01:00
Ruben Fiszel
834e7b1d1c todo: improve deleting tab 2023-02-24 01:04:26 +01:00
Ruben Fiszel
6e9a5b026e tab rework v2 2023-02-23 23:39:57 +01:00
Ruben Fiszel
7ad8879b09 fix binding 2023-02-23 22:14:23 +01:00
Ruben Fiszel
27cac3ffe6 fix(frontend): containers and tab fixes v1 2023-02-23 21:42:21 +01:00
Ruben Fiszel
705703a5e2 fix(frontend): containers and tab fixes v1 2023-02-23 21:01:47 +01:00
Ruben Fiszel
fac31c6628 fix(frontend): containers and tab fixes v1 2023-02-23 19:59:23 +01:00
74 changed files with 3367 additions and 563 deletions

View File

@@ -1,6 +1,73 @@
# Changelog
## [1.70.1](https://github.com/windmill-labs/windmill/compare/v1.70.0...v1.70.1) (2023-02-27)
### Bug Fixes
* **cli:** make cli resilient to systems without openable browsers ([c051ffe](https://github.com/windmill-labs/windmill/commit/c051ffeb42c1cff609f93da7745036ea722e17d4))
* **frontend:** Disable move in nested subgrid ([#1238](https://github.com/windmill-labs/windmill/issues/1238)) ([70eab30](https://github.com/windmill-labs/windmill/commit/70eab303bd45111ae198d9b710bfd6f9f59e53b0))
* **frontend:** Fix inline scripts list ([#1240](https://github.com/windmill-labs/windmill/issues/1240)) ([97602ac](https://github.com/windmill-labs/windmill/commit/97602ac6db1404d36d160a431ffcea6c0f567a48))
* **frontend:** Fix subgrid lock ([#1232](https://github.com/windmill-labs/windmill/issues/1232)) ([8ee9d67](https://github.com/windmill-labs/windmill/commit/8ee9d67f4faa91446338b41c664ef91913eb8b81))
## [1.70.1](https://github.com/windmill-labs/windmill/compare/v1.70.0...v1.70.1) (2023-02-27)
### Bug Fixes
* **cli:** make cli resilient to systems without openable browsers ([c051ffe](https://github.com/windmill-labs/windmill/commit/c051ffeb42c1cff609f93da7745036ea722e17d4))
* **frontend:** Disable move in nested subgrid ([#1238](https://github.com/windmill-labs/windmill/issues/1238)) ([70eab30](https://github.com/windmill-labs/windmill/commit/70eab303bd45111ae198d9b710bfd6f9f59e53b0))
* **frontend:** Fix subgrid lock ([#1232](https://github.com/windmill-labs/windmill/issues/1232)) ([8ee9d67](https://github.com/windmill-labs/windmill/commit/8ee9d67f4faa91446338b41c664ef91913eb8b81))
## [1.70.0](https://github.com/windmill-labs/windmill/compare/v1.69.3...v1.70.0) (2023-02-27)
### Features
* **apps:** add ag grid ([b690d80](https://github.com/windmill-labs/windmill/commit/b690d801d4aa5695ee558e81d1ed114074dfcb83))
* **frontend:** move to other grid ([#1230](https://github.com/windmill-labs/windmill/issues/1230)) ([104e4ac](https://github.com/windmill-labs/windmill/commit/104e4ac5e790c30e6fb6b27726776693038d4f19))
### Bug Fixes
* app setup and sync now uses 1.69.3 ([d38aff2](https://github.com/windmill-labs/windmill/commit/d38aff2fe228f23eb18c3991392928c064e6aca2))
* **frontend:** Fix duplication ([#1237](https://github.com/windmill-labs/windmill/issues/1237)) ([e87f4fc](https://github.com/windmill-labs/windmill/commit/e87f4fc44b847a573f5acafc0348fbcbfcb2258f))
* **frontend:** fix graph viewer id assignment ([e1f686d](https://github.com/windmill-labs/windmill/commit/e1f686d8508cfc1f73c43be08facc44217ca8de0))
## [1.69.3](https://github.com/windmill-labs/windmill/compare/v1.69.2...v1.69.3) (2023-02-24)
### Bug Fixes
* **deno:** fix denoify buffer handling ([c2e5afd](https://github.com/windmill-labs/windmill/commit/c2e5afd4e07fb63375832f308da8c744616ee188))
## [1.69.2](https://github.com/windmill-labs/windmill/compare/v1.69.1...v1.69.2) (2023-02-24)
### Bug Fixes
* **app:** fix all nested behavior ([dd28308](https://github.com/windmill-labs/windmill/commit/dd28308c3cf1877ba3f19dcd2bd20bf1c7896a99))
* **frontend:** delete grid item ([008c30f](https://github.com/windmill-labs/windmill/commit/008c30fcaad64af512407f9889a9881fafac0868))
* **frontend:** duplicate ([483407c](https://github.com/windmill-labs/windmill/commit/483407cdf0e1ed61de180a904934e950fed4adc3))
* **frontend:** Fix findGridItem ([a8295d0](https://github.com/windmill-labs/windmill/commit/a8295d0b5acd08cec42b7939d907df5c25132644))
* **frontend:** Fix findGridItem ([5bb77ed](https://github.com/windmill-labs/windmill/commit/5bb77edf45740a75e969b1bef31580271c9d5505))
* **frontend:** Fix next id ([8ddcf4d](https://github.com/windmill-labs/windmill/commit/8ddcf4d9c1a8d6dd20ee241a3f308811c49e58f1))
* **frontend:** gridtab ([fa105b4](https://github.com/windmill-labs/windmill/commit/fa105b4caeaa2d0e9704a48f6caf8d846839c23e))
* **frontend:** rewrote utils ([ea1b2c2](https://github.com/windmill-labs/windmill/commit/ea1b2c29b95282df347ef9c5973917fa3880e843))
* **frontend:** wip ([33ebe2d](https://github.com/windmill-labs/windmill/commit/33ebe2da8e81476be62a2567d5012573a8a010b6))
## [1.69.1](https://github.com/windmill-labs/windmill/compare/v1.69.0...v1.69.1) (2023-02-24)
### Bug Fixes
* **deno:** remove mysql support waiting for deno fix ([dd7e8c7](https://github.com/windmill-labs/windmill/commit/dd7e8c742c83f6a1d13e4343ca626c0b5efc06fb))
* **deno:** remove mysql support waiting for deno fix ([2f78132](https://github.com/windmill-labs/windmill/commit/2f78132e081bdf3d7468e022f0e981ebfa52cfb3))
* **frontend:** containers and tab fixes v1 ([27cac3f](https://github.com/windmill-labs/windmill/commit/27cac3ffe69c4dac160e9e55ffd1eb8ea348d487))
* **frontend:** containers and tab fixes v1 ([705703a](https://github.com/windmill-labs/windmill/commit/705703a5e2f2dc7ceb4c215221f72bf624799841))
* **frontend:** containers and tab fixes v1 ([fac31c6](https://github.com/windmill-labs/windmill/commit/fac31c6628b289ad6aae92434e312c4be281a4d2))
## [1.69.0](https://github.com/windmill-labs/windmill/compare/v1.68.0...v1.69.0) (2023-02-23)

104
backend/Cargo.lock generated
View File

@@ -255,9 +255,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.6.7"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fb79c228270dcf2426e74864cabc94babb5dbab01a4314e702d2f16540e1591"
checksum = "6137c6234afb339e75e764c866e3594900f0211e1315d33779f269bbe2ec6967"
dependencies = [
"async-trait",
"axum-core",
@@ -324,9 +324,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
[[package]]
name = "base64ct"
version = "1.5.3"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "better_scoped_tls"
@@ -553,9 +553,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
dependencies = [
"os_str_bytes",
]
@@ -581,9 +581,9 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
[[package]]
name = "const_format"
@@ -619,7 +619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
dependencies = [
"percent-encoding",
"time 0.3.19",
"time 0.3.20",
"version_check",
]
@@ -987,9 +987,9 @@ dependencies = [
[[package]]
name = "ena"
version = "0.14.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
dependencies = [
"log",
]
@@ -2149,18 +2149,18 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.5.10"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0072973714303aa6e3631c7e8e777970cf4bdd25dc4932e41031027b8bcc4e"
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.10"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0629cbd6b897944899b1f10496d9c4a7ac5878d45fd61bc22e9e79bfbbc29597"
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -2798,15 +2798,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "reqwest"
version = "0.11.14"
@@ -3003,7 +2994,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
source = "git+https://github.com/RustPython/RustPython#351d464448607413dc12de6905f1165f8d45af54"
dependencies = [
"num-bigint",
"rustpython-compiler-core",
@@ -3012,7 +3003,7 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
source = "git+https://github.com/RustPython/RustPython#351d464448607413dc12de6905f1165f8d45af54"
dependencies = [
"bincode",
"bitflags",
@@ -3029,7 +3020,7 @@ dependencies = [
[[package]]
name = "rustpython-parser"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
source = "git+https://github.com/RustPython/RustPython#351d464448607413dc12de6905f1165f8d45af54"
dependencies = [
"ahash",
"anyhow",
@@ -3083,9 +3074,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
dependencies = [
"chrono",
"dyn-clone",
@@ -3097,9 +3088,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
dependencies = [
"proc-macro2",
"quote",
@@ -3823,9 +3814,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.108"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
@@ -3840,16 +3831,15 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "tempfile"
version = "3.3.0"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
"rustix",
"windows-sys 0.42.0",
]
[[package]]
@@ -3926,9 +3916,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.19"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2"
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
dependencies = [
"itoa",
"serde",
@@ -3944,9 +3934,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
[[package]]
name = "time-macros"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c"
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
dependencies = [
"time-core",
]
@@ -4153,9 +4143,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.3.5"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858"
checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658"
dependencies = [
"bitflags",
"bytes",
@@ -4766,7 +4756,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"axum",
@@ -4793,7 +4783,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"argon2",
@@ -4826,7 +4816,7 @@ dependencies = [
"sql-builder",
"sqlx",
"tempfile",
"time 0.3.19",
"time 0.3.20",
"tokio",
"tokio-tar",
"tokio-util",
@@ -4848,7 +4838,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"base64 0.21.0",
"chrono",
@@ -4863,7 +4853,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"chrono",
"serde",
@@ -4876,7 +4866,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"axum",
@@ -4901,7 +4891,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"serde",
"serde_json",
@@ -4909,7 +4899,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"itertools",
@@ -4923,7 +4913,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"itertools",
@@ -4935,7 +4925,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"itertools",
@@ -4950,7 +4940,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"deno_core",
@@ -4964,7 +4954,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"chrono",
@@ -4987,7 +4977,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.69.0"
version = "1.70.1"
dependencies = [
"anyhow",
"async-recursion",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.69.0"
version = "1.70.1"
authors.workspace = true
edition.workspace = true
@@ -19,7 +19,7 @@ members = [
]
[workspace.package]
version = "1.69.0"
version = "1.70.1"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.69.0
version: 1.70.1
title: Windmill API
contact:

View File

@@ -6,10 +6,10 @@
* LICENSE-AGPL for a copy of the license.
*/
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
use std::str::FromStr;
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
use crate::BASE_URL;
use crate::{
apps::AppWithLastVersion,
@@ -20,7 +20,7 @@ use crate::{
utils::require_super_admin,
HTTP_CLIENT,
};
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
use axum::response::Redirect;
use axum::{
body::StreamBody,
@@ -30,7 +30,7 @@ use axum::{
routing::{delete, get, post},
Json, Router,
};
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
use stripe::CustomerId;
use windmill_audit::{audit_log, ActionKind};
use windmill_common::{
@@ -63,12 +63,13 @@ pub fn workspaced_service() -> Router {
.route("/tarball", get(tarball_workspace))
.route("/premium_info", get(premium_info));
#[cfg(enterprise)]
let router = {
router
.route("/checkout", get(stripe_checkout))
.route("/billing_portal", get(stripe_portal));
};
#[cfg(feature = "enterprise")]
tracing::info!("stripe enabled");
#[cfg(feature = "enterprise")]
let router = router
.route("/checkout", get(stripe_checkout))
.route("/billing_portal", get(stripe_portal));
router
}
@@ -230,13 +231,13 @@ async fn premium_info(
Ok(Json(row))
}
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
#[derive(Deserialize)]
struct PlanQuery {
plan: String,
}
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
async fn stripe_checkout(
authed: Authed,
Path(w_id): Path<String>,
@@ -302,7 +303,7 @@ async fn stripe_checkout(
}
}
#[cfg(enterprise)]
#[cfg(feature = "enterprise")]
async fn stripe_portal(
authed: Authed,
Path(w_id): Path<String>,

View File

@@ -351,7 +351,10 @@ pub async fn push<'c>(
.unwrap_or(false);
if !is_super_admin {
if usage > MAX_FREE_EXECS {
if usage > MAX_FREE_EXECS
&& !matches!(job_payload, JobPayload::Dependencies { .. })
&& !matches!(job_payload, JobPayload::FlowDependencies { .. })
{
return Err(error::Error::BadRequest(format!(
"User {email} has exceeded the free usage limit of {MAX_FREE_EXECS} that applies outside of premium workspaces."
)));
@@ -466,10 +469,10 @@ pub async fn push<'c>(
}
JobPayload::Flow(flow) => {
let value_json = sqlx::query_scalar!(
"SELECT value FROM flow WHERE path = $1 AND workspace_id = $2",
flow,
workspace_id
)
"SELECT value FROM flow WHERE path = $1 AND workspace_id = $2",
flow,
workspace_id
)
.fetch_optional(&mut tx)
.await?
.ok_or_else(|| Error::InternalErr(format!("not found flow at path {:?}", flow)))?;

View File

@@ -383,7 +383,7 @@ lazy_static::lazy_static! {
.unwrap();
static ref WORKER_UPTIME_OPTS: prometheus::Opts = prometheus::opts!(
"worker_uptime",
"Total number of milliseconds since the worker has started"
"Total number of seconds since the worker has started"
);
static ref TIMEOUT: u16 = std::env::var("TIMEOUT")
@@ -445,15 +445,11 @@ pub async fn run_worker(
insert_initial_ping(worker_instance, &worker_name, ip, db).await;
let uptime_metric = prometheus::register_int_counter!(WORKER_UPTIME_OPTS
let uptime_metric = prometheus::register_counter!(WORKER_UPTIME_OPTS
.clone()
.const_label("name", &worker_name))
.unwrap();
uptime_metric.inc_by(
((Instant::now() - start_time).as_millis() - uptime_metric.get() as u128)
.try_into()
.unwrap(),
);
let worker_execution_duration = prometheus::register_histogram_vec!(
prometheus::HistogramOpts::new(
@@ -465,6 +461,14 @@ pub async fn run_worker(
)
.expect("register prometheus metric");
let worker_execution_duration_counter = prometheus::register_counter!(prometheus::opts!(
"worker_execution_duration_counter",
"Total number of seconds spent executing jobs"
)
.const_label("name", &worker_name))
.expect("register prometheus metric");
let worker_sleep_duration = prometheus::register_histogram!(prometheus::HistogramOpts::new(
"worker_sleep_duration",
"Duration sleeping waiting for job",
@@ -472,6 +476,15 @@ pub async fn run_worker(
.const_label("name", &worker_name),)
.expect("register prometheus metric");
let worker_sleep_duration_counter = prometheus::register_counter!(prometheus::opts!(
"worker_execution_sleep_counter",
"Total number of seconds spent sleeping between pulling jobs from the queue"
)
.const_label("name", &worker_name))
.expect("register prometheus metric");
let worker_pull_duration = prometheus::register_histogram!(prometheus::HistogramOpts::new(
"worker_pull_duration",
"Duration pulling next job",
@@ -479,6 +492,13 @@ pub async fn run_worker(
.const_label("name", &worker_name),)
.expect("register prometheus metric");
let worker_pull_duration_counter = prometheus::register_counter!(prometheus::opts!(
"worker_pull_sleep_counter",
"Total number of seconds spent pulling jobs (if growing large the db is undersized)"
)
.const_label("name", &worker_name))
.expect("register prometheus metric");
let worker_execution_failed = prometheus::register_int_counter_vec!(
prometheus::Opts::new("worker_execution_failed", "Number of failed jobs",)
.const_label("name", &worker_name),
@@ -526,11 +546,12 @@ pub async fn run_worker(
worker_busy.set(0);
uptime_metric.inc_by(
((Instant::now() - start_time).as_millis() - uptime_metric.get() as u128)
(((Instant::now() - start_time).as_millis() as f64)/1000.0 - uptime_metric.get())
.try_into()
.unwrap(),
);
let do_break = async {
if last_ping.elapsed().as_secs() > NUM_SECS_ENV_CHECK {
sqlx::query!(
@@ -574,7 +595,8 @@ pub async fn run_worker(
(job, timer) = {
let timer = worker_pull_duration.start_timer();
pull(&db, WHITELIST_WORKSPACES.clone(), BLACKLIST_WORKSPACES.clone()).map(|x| (x, timer)) } => {
drop(timer);
let duration_pull_s = timer.stop_and_record();
worker_pull_duration_counter.inc_by(duration_pull_s);
(false, job)
},
}
@@ -680,6 +702,8 @@ pub async fn run_worker(
.await;
};
let duration = _timer.stop_and_record();
worker_execution_duration_counter.inc_by(duration);
if !*KEEP_JOB_DIR && !(is_flow && same_worker) {
let _ = tokio::fs::remove_dir_all(job_dir).await;
@@ -689,9 +713,9 @@ pub async fn run_worker(
let _timer = worker_sleep_duration
.start_timer();
tokio::time::sleep(Duration::from_millis(*SLEEP_QUEUE)).await;
let duration = _timer.stop_and_record();
worker_sleep_duration_counter.inc_by(duration);
}
Err(err) => {
tracing::error!(worker = %worker_name, "run_worker: pulling jobs: {}", err);

View File

@@ -1,6 +1,6 @@
// windmill
export { setClient } from "https://deno.land/x/windmill@v1.66.0/mod.ts";
export * from "https://deno.land/x/windmill@v1.66.0/windmill-api/index.ts";
export { setClient } from "https://deno.land/x/windmill@v1.69.3/mod.ts";
export * from "https://deno.land/x/windmill@v1.69.3/windmill-api/index.ts";
// cliffy
export { Command } from "https://deno.land/x/cliffy@v0.25.7/command/command.ts";

View File

@@ -51,9 +51,11 @@ export async function browserLogin(
const url = `${baseUrl}user/cli?port=${port}`
console.log(`Login by going to ${url}`);
try {
open(url)
await open(url)
console.log("Opened browser for you");
} catch { }
} catch {
console.error(`Failed to open browser, please navigate to ${url}`)
}
const firstConnection = await server.accept();
const httpFirstConnection = Deno.serveHttp(firstConnection);
const firstRequest = (await httpFirstConnection.nextRequest())!;

View File

@@ -13,7 +13,7 @@ import sync from "./sync.ts";
import { tryResolveVersion } from "./context.ts";
import { GlobalOptions } from "./types.ts";
const VERSION = "v1.69.0";
const VERSION = "v1.70.1";
let command: any = new Command()
.name("wmill")

View File

@@ -9,7 +9,7 @@
"lock": "",
"path": null,
"type": "rawscript",
"content": "// import * as wmill from \"https://deno.land/x/windmill@v1.50.0/mod.ts\"\n\nexport async function main(x: string) {\n console.log(\"Hello from Deno! The argument x is \" + x);\n return x;\n}\n",
"content": "// import * as wmill from \"https://deno.land/x/windmill@v1.69.3/mod.ts\"\n\nexport async function main(x: string) {\n console.log(\"Hello from Deno! The argument x is \" + x);\n return x;\n}\n",
"language": "deno",
"input_transforms": {
"x": {

View File

@@ -4,8 +4,9 @@ set -e
npm ci --ignore-scripts
npx --yes openapi-typescript-codegen --input ../backend/windmill-api/openapi.yaml \
--output ./src --useOptions \
&& sed -i '213 i \\ request.referrerPolicy = \"no-referrer\"\n' src/core/request.ts
npx --yes denoify
&& sed -i '213 i \\ request.referrerPolicy = \"no-referrer\"\n' src/core/request.ts
npx --yes denoify
rm -rf windmill-api
mv deno_dist windmill-api
sed -i 's/buffer DENOIFY: UNKNOWN NODE BUILTIN/node:buffer/' ./windmill-api/core/request.ts
rm -rf src/

View File

@@ -14,7 +14,6 @@ BigInt.prototype.toJSON = function () {
};
export { pgSql, pgClient } from './pg.ts'
export { mySql, mysqlClient } from './mysql.ts'
export type Sql = string
export type Email = string

View File

@@ -1,12 +1,12 @@
{
"name": "windmill",
"version": "1.69.0",
"version": "1.70.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "windmill",
"version": "1.69.0",
"version": "1.70.1",
"dependencies": {
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
@@ -14,11 +14,13 @@
"@popperjs/core": "^2.11.6",
"@redocly/json-to-json-schema": "^0.0.1",
"@tanstack/svelte-table": "^8.7.6",
"ag-grid-svelte": "^0.1.4",
"async-mutex": "^0.4.0",
"chart.js": "^3.9.1",
"chartjs-adapter-date-fns": "^3.0.0",
"chartjs-plugin-zoom": "^2.0.0",
"date-fns": "^2.29.3",
"fast-equals": "^4.0.3",
"highlight.js": "^11.7.0",
"lucide-svelte": "^0.115.0",
"monaco-editor": "0.33.0",
@@ -43,7 +45,7 @@
"@types/vscode": "~1.74.0",
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.48.0",
"@windmill-labs/svelte-grid": "^5.1.3",
"@windmill-labs/svelte-grid": "^5.1.4",
"@windmill-labs/svelvet": "^4.0.20",
"@zerodevx/svelte-toast": "^0.8.1",
"autoprefixer": "^10.4.13",
@@ -1263,9 +1265,9 @@
}
},
"node_modules/@windmill-labs/svelte-grid": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.3.tgz",
"integrity": "sha512-SzfuJ2qYkBYC73x3l+x9l7WcgU+kMlRoFkCgSCOfggi3z5zJU9eX1VYsV1wDjtQVU9OUaAciv1xlUR4OPxrFlg==",
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.4.tgz",
"integrity": "sha512-alxQ8su/osmHodl1JMta+0dvlc2qnYwiXsoeC8Ys8hrLywD03y5tjxYV0L0WXvOnMKG1S9GbqGuDVCk+UmVuKg==",
"dev": true
},
"node_modules/@windmill-labs/svelvet": {
@@ -1357,6 +1359,23 @@
"node": ">=0.4.0"
}
},
"node_modules/ag-grid-community": {
"version": "28.2.1",
"resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-28.2.1.tgz",
"integrity": "sha512-DMZh/xD/FqYP17qJ1M92PolTYe+hrKuEaf+A4h13O6qn2x/xZQrTRGW5DgnQLR/uLMe1XXZQPKR3UKgAlKo69A==",
"peer": true
},
"node_modules/ag-grid-svelte": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/ag-grid-svelte/-/ag-grid-svelte-0.1.4.tgz",
"integrity": "sha512-yKJKZ1o3aE9dgaK4WtmjG+vA9GKqErznvFisDnzi+PPGWXDCSNWuoDGCUpEFJtHKrfooLoUZZHYHi8I9sZ+BCA==",
"dependencies": {
"svelte": "^3.55.0"
},
"peerDependencies": {
"ag-grid-community": "^28"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -2971,6 +2990,11 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/fast-equals": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz",
"integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg=="
},
"node_modules/fast-glob": {
"version": "3.2.12",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
@@ -7904,9 +7928,9 @@
}
},
"@windmill-labs/svelte-grid": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.3.tgz",
"integrity": "sha512-SzfuJ2qYkBYC73x3l+x9l7WcgU+kMlRoFkCgSCOfggi3z5zJU9eX1VYsV1wDjtQVU9OUaAciv1xlUR4OPxrFlg==",
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.4.tgz",
"integrity": "sha512-alxQ8su/osmHodl1JMta+0dvlc2qnYwiXsoeC8Ys8hrLywD03y5tjxYV0L0WXvOnMKG1S9GbqGuDVCk+UmVuKg==",
"dev": true
},
"@windmill-labs/svelvet": {
@@ -7980,6 +8004,20 @@
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
"dev": true
},
"ag-grid-community": {
"version": "28.2.1",
"resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-28.2.1.tgz",
"integrity": "sha512-DMZh/xD/FqYP17qJ1M92PolTYe+hrKuEaf+A4h13O6qn2x/xZQrTRGW5DgnQLR/uLMe1XXZQPKR3UKgAlKo69A==",
"peer": true
},
"ag-grid-svelte": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/ag-grid-svelte/-/ag-grid-svelte-0.1.4.tgz",
"integrity": "sha512-yKJKZ1o3aE9dgaK4WtmjG+vA9GKqErznvFisDnzi+PPGWXDCSNWuoDGCUpEFJtHKrfooLoUZZHYHi8I9sZ+BCA==",
"requires": {
"svelte": "^3.55.0"
}
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -9151,6 +9189,11 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"fast-equals": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz",
"integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg=="
},
"fast-glob": {
"version": "3.2.12",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "windmill",
"version": "1.69.0",
"version": "1.70.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
@@ -25,7 +25,7 @@
"@types/vscode": "~1.74.0",
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.48.0",
"@windmill-labs/svelte-grid": "^5.1.3",
"@windmill-labs/svelte-grid": "^5.1.4",
"@windmill-labs/svelvet": "^4.0.20",
"@zerodevx/svelte-toast": "^0.8.1",
"autoprefixer": "^10.4.13",
@@ -66,11 +66,13 @@
"@popperjs/core": "^2.11.6",
"@redocly/json-to-json-schema": "^0.0.1",
"@tanstack/svelte-table": "^8.7.6",
"ag-grid-svelte": "^0.1.4",
"async-mutex": "^0.4.0",
"chart.js": "^3.9.1",
"chartjs-adapter-date-fns": "^3.0.0",
"chartjs-plugin-zoom": "^2.0.0",
"date-fns": "^2.29.3",
"fast-equals": "^4.0.3",
"highlight.js": "^11.7.0",
"lucide-svelte": "^0.115.0",
"monaco-editor": "0.33.0",

View File

@@ -44,7 +44,7 @@ declare module '@windmill-labs/svelte-grid' {
fastStart?: boolean
throttleUpdate?: number
throttleResize?: number
onTopId?: string
scroller?: undefined
sensor?: number
}
@@ -60,7 +60,7 @@ declare module '@windmill-labs/svelte-grid' {
mount: CustomEvent<>
},
Slots<T>
> {}
> { }
}
declare module '@windmill-labs/svelte-grid/build/helper/index.mjs' {

View File

@@ -396,7 +396,7 @@
bind:error={pathError}
bind:path
initialPath=""
namePlaceholder="my_{resource_type}"
namePlaceholder="{resource_type}"
kind="resource"
/>
@@ -433,7 +433,7 @@
{:else}
<Path
initialPath=""
namePlaceholder="my_{resource_type}"
namePlaceholder="{resource_type}"
bind:error={pathError}
bind:path
kind="resource"

View File

@@ -138,8 +138,18 @@
export function setCode(ncode: string): void {
code = ncode
if (editor) {
editor.setValue(ncode)
if (editor?.getModel()) {
// editor.setValue(ncode)
editor.pushUndoStop()
editor.executeEdits('set', [
{
range: editor.getModel()!.getFullModelRange(), // full range
text: ncode
}
])
editor.pushUndoStop()
}
}

View File

@@ -22,6 +22,7 @@
import Tooltip from './Tooltip.svelte'
import FolderEditor from './FolderEditor.svelte'
import GroupEditor from './GroupEditor.svelte'
import { random_adj } from './random_positive_adjetive'
type PathKind = 'resource' | 'script' | 'variable' | 'flow' | 'schedule' | 'app'
let meta: Meta | undefined = undefined
@@ -69,15 +70,23 @@
export async function reset() {
if (path == '' || path == 'u//') {
meta = { ownerKind: 'user', name: namePlaceholder, owner: '' }
meta = {
ownerKind: 'user',
name: random_adj() + '_' + namePlaceholder,
owner: ''
}
meta.owner = $userStore!.username.split('@')[0]
let i = 1
while (await pathExists(metaToPath(meta), kind)) {
meta.name = `${namePlaceholder}_${i}`
i += 1
let newMeta = { ...meta }
while (await pathExists(metaToPath(newMeta), kind)) {
disabled = true
error = 'finding an available name...'
newMeta.name = random_adj() + '_' + namePlaceholder
}
error = ''
disabled = false
meta = newMeta
path = metaToPath(meta)
} else {
meta = pathToMeta(path)

View File

@@ -144,7 +144,7 @@
disabled={!can_write}
bind:path
{initialPath}
namePlaceholder="my_resource"
namePlaceholder="resource"
kind="resource"
/>
</div>

View File

@@ -180,7 +180,7 @@
bind:error={pathError}
bind:path
{initialPath}
namePlaceholder={'my_schedule'}
namePlaceholder="schedule"
kind="schedule"
/>
<div class="mb-8" />

View File

@@ -24,6 +24,7 @@
export let initialPath: string = ''
export let template: 'pgsql' | 'mysql' | 'script' = 'script'
export let initialArgs: Record<string, any> = {}
export let lockedLanguage = false
const langs: [string, SupportedLanguage][] = [
['Typescript', Script.language.DENO],
@@ -204,7 +205,7 @@
bind:path={script.path}
{initialPath}
on:enter={() => changeStep(2)}
namePlaceholder="my_script"
namePlaceholder="script"
kind="script"
/>
<h2 class="border-b pb-1 mt-12 mb-4">Summary</h2>
@@ -214,7 +215,13 @@
bind:value={script.summary}
placeholder="Short summary to be displayed when listed"
/>
<h2 class="border-b pb-1 mt-12 mb-6">Language</h2>
{#if lockedLanguage}
<div class="text-sm text-gray-600 italic mb-2">
As a forked script, the language '{script.language}' cannot be modified.
</div>
{/if}
<div class="flex flex-row gap-2 flex-wrap">
{#each langs as [label, lang]}
{@const isPicked = script.language == lang && template == 'script'}
@@ -228,6 +235,7 @@
template = 'script'
initContent(lang, script.kind, template)
}}
disabled={lockedLanguage}
>
<LanguageIcon {lang} /><span class="ml-2 py-4">{label}</span>
</Button>
@@ -237,6 +245,7 @@
variant="border"
color={template == 'pgsql' ? 'blue' : 'dark'}
btnClasses={template == 'pgsql' ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
disabled={lockedLanguage}
on:click={() => {
script.language = Script.language.DENO
template = 'pgsql'
@@ -245,7 +254,7 @@
>
<LanguageIcon lang="pgsql" /><span class="ml-2 py-4">PostgreSQL</span>
</Button>
<Button
<!-- <Button
size="sm"
variant="border"
color={template == 'mysql' ? 'blue' : 'dark'}
@@ -257,7 +266,7 @@
}}
>
<LanguageIcon lang="mysql" /><span class="ml-2 py-4">MySQL</span>
</Button>
</Button> -->
</div>
<div class="mt-16 mb-4">
<Button

View File

@@ -101,6 +101,7 @@
onMount(() => {
inferSchema(code)
loadPastTests()
})
</script>

View File

@@ -148,7 +148,7 @@
bind:error={pathError}
bind:path
{initialPath}
namePlaceholder="my_variable"
namePlaceholder="variable"
kind="variable"
/>
</div>

View File

@@ -95,7 +95,6 @@
<InputValue {id} input={configuration.triggerOnAppLoad} bind:value={triggerOnAppLoad} />
<InputValue
row={extraQueryParams['row']}
{id}
input={configuration.disabled}
bind:value={disabled}

View File

@@ -69,7 +69,6 @@
<InputValue {id} input={configuration.color} bind:value={color} />
<InputValue {id} input={configuration.size} bind:value={size} />
<InputValue
row={extraQueryParams['row']}
{id}
input={configuration.disabled}
bind:value={disabled}

View File

@@ -3,7 +3,7 @@
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
type FitOption = typeof staticValues['objectFitOptions'][number]
type FitOption = (typeof staticValues)['objectFitOptions'][number]
export let id: string
export let configuration: Record<string, AppInput>
@@ -12,7 +12,7 @@
const fit: Record<FitOption, string> = {
cover: 'object-cover',
contain: 'object-contain',
fill: 'object-fill',
fill: 'object-fill'
}
let source: string | undefined = undefined
@@ -27,8 +27,9 @@
<InputValue {id} input={configuration.customStyles} bind:value={customStyles} />
<img
on:pointerdown|preventDefault
src={source}
alt={altText}
style={customStyles}
class="w-full h-full {fit[imageFit || 'cover']}"
>
/>

View File

@@ -0,0 +1,110 @@
<script lang="ts">
import AgGridSvelte from 'ag-grid-svelte/AgGridSvelte.svelte'
import 'ag-grid-community/styles/ag-grid.css'
import 'ag-grid-community/styles/ag-theme-alpine.css'
import { getContext, onMount } from 'svelte'
import type { Output } from '../../../rx'
import type { AppEditorContext } from '../../../types'
import InputValue from '../../helpers/InputValue.svelte'
import type { AppInput } from '../../../inputType'
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
import { isObject } from '$lib/utils'
import Alert from '$lib/components/common/alert/Alert.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export const staticOutputs: string[] = ['selectedRow', 'loading', 'result', 'selectedRowIndex']
let result: Record<string, any>[] | undefined = undefined
const {
worldStore,
staticOutputs: staticOutputsStore,
selectedComponent
} = getContext<AppEditorContext>('AppEditorContext')
let selectedRowIndex = -1
function toggleRow(row: Record<string, any>, rowIndex: number) {
if (selectedRowIndex !== rowIndex) {
selectedRowIndex = rowIndex
outputs?.selectedRow.set(row.original)
outputs?.selectedRowIndex.set(rowIndex)
}
}
let mounted = false
onMount(() => {
mounted = true
})
$: selectedRowIndex === -1 &&
Array.isArray(result) &&
result.length > 0 &&
// We need to wait until the component is mounted so the world is created
mounted &&
outputs &&
toggleRow({ original: result[0] }, 0)
$: outputs = $worldStore?.outputsById[id] as {
selectedRowIndex: Output<number>
selectedRow: Output<any>
result: Output<any>
}
$: outputs?.result?.set(result)
let clientHeight
let clientWidth
let columnDefs: any = undefined
let allEditable: boolean | undefined = undefined
function onCellValueChanged(event) {
if (result) {
let dataCell = event.newValue
try {
dataCell = JSON.parse(dataCell)
} catch (e) {}
result[event.node.rowIndex][event.column.colId] = dataCell
}
}
</script>
<InputValue {id} input={configuration.columnDefs} bind:value={columnDefs} />
<InputValue {id} input={configuration.allEditable} bind:value={allEditable} />
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if Array.isArray(result) && result.every(isObject)}
<div
class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full"
bind:clientHeight
bind:clientWidth
>
<div
on:pointerdown|stopPropagation={() => {
$selectedComponent = id
}}
style:height="{clientHeight}px"
style:width="{clientWidth}px"
class="ag-theme-alpine"
>
<AgGridSvelte
bind:rowData={result}
{columnDefs}
defaultColDef={{ flex: 1, editable: allEditable, onCellValueChanged }}
/>
</div>
</div>
{:else if result != undefined}
<Alert title="Parsing issues" type="error" size="xs">
The result should be an array of objects
</Alert>
{/if}
</RunnableWrapper>

View File

@@ -10,21 +10,17 @@
export let input: AppInput
export let value: T
export let id: string | undefined = undefined
export let row: Record<string, any> | undefined = {}
export let error: string = ''
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
$: state = $worldStore?.state
$: input && $worldStore && row && handleConnection()
$: input && $worldStore && handleConnection()
$: input && input.type == 'template' && $state && (value = getValue(input))
$: input && input.type == 'eval' && $state && (value = evalExpr(input))
function handleConnection() {
if (input.type === 'connected') {
$worldStore?.connect<any>(input, onValueChange)
} else if (input.type === 'row') {
setTimeout(() => (value = row?.[input['column']]), 0)
} else if (input.type === 'static' || input.type == 'template') {
setTimeout(() => (value = getValue(input)), 0)
} else if (input.type == 'eval') {
@@ -57,7 +53,6 @@
Object.fromEntries(Object.entries(value ?? {}).map((x) => [x[0], x[1].peak()]))
]
})
.concat(row ? [['row', row]] : [])
)
}

View File

@@ -239,12 +239,7 @@
{#each Object.entries(fields ?? {}) as [key, v]}
{#if v.type != 'static' && v.type != 'user'}
<InputValue
{id}
input={fields[key]}
bind:value={runnableInputValues[key]}
row={extraQueryParams['row'] ?? {}}
/>
<InputValue {id} input={fields[key]} bind:value={runnableInputValues[key]} />
{/if}
{/each}

View File

@@ -23,7 +23,13 @@
result: Output<string | undefined>
}
let value: string | undefined = undefined
// $: outputs && handleOutputs()
// function handleOutputs() {
// value = outputs.result.peak()
// }
let value: string | undefined = outputs?.result.peak()
$: items && handleItems()
@@ -38,9 +44,15 @@
}
})
: []
if (items?.[0]?.['value'] != value) {
value = JSON.stringify(items?.[0]?.['value'])
outputs?.result.set(value)
const valuePeak = outputs?.result.peak()
if (!valuePeak) {
const value0 = items?.[0]?.['value']
if (value0 != value && !items.includes(value0)) {
value = JSON.stringify(value0)
outputs?.result.set(value0)
}
} else {
value = valuePeak
}
}
@@ -74,6 +86,12 @@
$selectedComponent = id
}
}}
on:focus={() => {
$selectedComponent = id
}}
floatingConfig={{
strategy: 'fixed'
}}
/>
</div>
</AlignWrapper>
@@ -82,4 +100,7 @@
.app-select .value-container {
padding: 0 !important;
}
.svelte-select-list {
z-index: 1000 !important;
}
</style>

View File

@@ -13,8 +13,7 @@
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let values: [number] = [0]
const { worldStore, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
let min = 0
let max = 42
let step = 1
@@ -22,7 +21,12 @@
$: outputs = $worldStore?.outputsById[id] as {
result: Output<number | null>
}
$: if (values) {
let values: [number] = [outputs?.result.peak() ?? 0]
$: values && handleValues()
function handleValues() {
// Disallow 'e' character in numbers
// if(value && value.toString().includes('e')) {
// value = +value.toString().replaceAll('e', '')
@@ -40,7 +44,7 @@
<AlignWrapper {verticalAlignment}>
<div class="flex items-center w-full gap-1 px-1">
<span>{min}</span>
<div class="grow" on:pointerdown|stopPropagation>
<div class="grow" on:pointerdown|stopPropagation={() => ($selectedComponent = id)}>
<RangeSlider {step} min={min ?? 0} max={max ?? 1} bind:values />
</div>
<span>{max}</span>

View File

@@ -4,19 +4,16 @@
import type { AppInput } from '../../inputType'
import type { AppEditorContext, GridItem } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let initializing: boolean | undefined = undefined
export let configuration: Record<string, AppInput>
export let subGrids: GridItem[][] | undefined = undefined
export let componentContainerHeight: number
export const staticOutputs: string[] = ['loading', 'result']
const { focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
let noPadding: boolean | undefined = undefined
export const staticOutputs: string[] = []
const { app, focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
let result: string[] | undefined = undefined
let gridContent: string[] | undefined = undefined
function onFocus() {
@@ -29,15 +26,16 @@
$: $selectedComponent === id && onFocus()
</script>
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if subGrids && subGrids[0]}
<SubGridEditor
bind:subGrid={subGrids[0]}
containerHeight={componentContainerHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/if}
</RunnableWrapper>
{#if $app.subgrids?.[`${id}-0`]}
<SubGridEditor
{noPadding}
bind:subGrid={$app.subgrids[`${id}-0`]}
containerHeight={componentContainerHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/if}

View File

@@ -6,27 +6,23 @@
import type { Output } from '../../rx'
import type { AppEditorContext, GridItem } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let initializing: boolean | undefined = undefined
export let configuration: Record<string, AppInput>
export let subGrids: GridItem[][] | undefined = undefined
export let componentContainerHeight: number
export let tabs: string[]
export const staticOutputs: string[] = ['loading', 'result', 'selectedTabIndex']
const { worldStore, focusedGrid, selectedComponent } =
export const staticOutputs: string[] = ['selectedTabIndex']
const { app, worldStore, focusedGrid, selectedComponent } =
getContext<AppEditorContext>('AppEditorContext')
let result: string[] | undefined = undefined
let gridContent: string[] | undefined = undefined
let selected: string = ''
let noPadding: boolean | undefined = undefined
$: selectedIndex = result?.indexOf(selected) ?? -1
$: selectedIndex = tabs?.indexOf(selected) ?? -1
$: if (result && selected === '') {
selected = result[0]
$: if ((tabs && selected === '') || !tabs.includes(selected)) {
selected = tabs[0]
}
$: outputs = $worldStore?.outputsById[id] as {
@@ -38,6 +34,7 @@
}
$: selectedIndex >= 0 && handleTabSelection()
let tabHeight: number = 0
function onFocus() {
@@ -50,24 +47,30 @@
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
</script>
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
<div bind:clientHeight={tabHeight}>
<InputValue {id} input={configuration.tabs} bind:value={tabs} />
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<div>
<div bind:clientHeight={tabHeight} on:pointerdown|stopPropagation>
<Tabs bind:selected>
{#each result ?? [] as res}
{#each tabs ?? [] as res}
<Tab value={res}>
<span class="font-semibold">{res}</span>
</Tab>
{/each}
</Tabs>
</div>
{#if subGrids && subGrids[selectedIndex]}
<SubGridEditor
bind:subGrid={subGrids[selectedIndex]}
containerHeight={componentContainerHeight - tabHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{#if $app.subgrids}
{#each tabs ?? [] as res, i}
<SubGridEditor
visible={i === selectedIndex}
bind:subGrid={$app.subgrids[`${id}-${i}`]}
{noPadding}
containerHeight={componentContainerHeight - tabHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/each}
{/if}
</RunnableWrapper>
</div>

View File

@@ -241,7 +241,7 @@
bind:error={pathError}
bind:path={newPath}
initialPath=""
namePlaceholder="my_app"
namePlaceholder="app"
kind="app"
/>
@@ -467,8 +467,8 @@
<div>{`Sub grid: ${$focusedGrid.parentComponentId} (${$focusedGrid.subGridIndex})`}</div>
<button
on:click={() => {
$focusedGrid = undefined
$selectedComponent = undefined
$focusedGrid = undefined
}}
>
<X size={14} />

View File

@@ -37,13 +37,17 @@
const disabledGridItem = fct(gridItem)
if (disabledGridItem.data.subGrids) {
disabledGridItem.data.subGrids = disabledGridItem.data.subGrids.map((subgrid: GridItem[]) =>
subgrid.map((subgridItem: GridItem) => fct(subgridItem))
disabledGridItem.data.subGrids = disabledGridItem.data.subGrids.map(
(subgrid: GridItem[]) => subgrid?.map((subgridItem: GridItem) => fct(subgridItem)) ?? []
)
}
return disabledGridItem
})
Object.values($app.subgrids ?? {}).map(
(subgrid: GridItem[]) => subgrid?.map((subgridItem: GridItem) => fct(subgridItem)) ?? []
)
}
function removeGridElement(component) {
@@ -87,6 +91,7 @@
function selectComponent(id: string) {
if (!$connectingInput.opened) {
$selectedComponent = id
$focusedGrid = undefined
}
}
@@ -126,7 +131,6 @@
})
}
})
let mounted = false
</script>
<div class="relative w-full z-20 overflow-visible">
@@ -151,8 +155,13 @@
on:pointerdown={onpointerdown}
on:pointerleave={onpointerup}
on:pointerup={onpointerup}
on:click={() => {
$selectedComponent = undefined
$focusedGrid = undefined
}}
>
<Grid
onTopId={$selectedComponent}
fillSpace={false}
bind:items={$app.grid}
let:dataItem
@@ -165,13 +174,11 @@
{#if gridComponent.data.id === dataItem.data.id}
<!-- svelte-ignore a11y-click-events-have-key-events -->
{#if $connectingInput.opened}
{#if $connectingInput.opened}
<div
on:pointerenter={() => ($connectingInput.hoveredComponent = gridComponent.data.id)}
on:pointerleave={() => ($connectingInput.hoveredComponent = undefined)}
class="absolute w-full h-full bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
/>
{/if}
<div
on:pointerenter={() => ($connectingInput.hoveredComponent = gridComponent.data.id)}
on:pointerleave={() => ($connectingInput.hoveredComponent = undefined)}
class="absolute w-full h-full bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
/>
<div
style="transform: translate(-50%, -50%);"
class="absolute w-fit justify-center bg-indigo-500/90 left-[50%] top-[50%] z-50 px-6 rounded border text-white py-2 text-5xl center-center"
@@ -180,6 +187,7 @@
{/if}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
on:click|stopPropagation
on:pointerdown={() => selectComponent(dataItem.data.id)}
class={classNames(
'h-full w-full center-center',
@@ -189,7 +197,7 @@
>
<Component
{pointerdown}
bind:component={gridComponent.data}
bind:pComponent={gridComponent.data}
selected={$selectedComponent === dataItem.data.id}
locked={isFixed(gridComponent)}
on:delete={() => removeGridElement(gridComponent.data)}

View File

@@ -1,36 +1,35 @@
<script lang="ts">
import { getContext } from 'svelte'
import type { AppEditorContext } from '../types'
import { allItems, allItemsWithParent } from '../utils'
import PanelSection from './settingsPanel/common/PanelSection.svelte'
import ComponentPanel from './settingsPanel/ComponentPanel.svelte'
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
import TablePanel from './TablePanel.svelte'
const { selectedComponent, lazyGrid, app } = getContext<AppEditorContext>('AppEditorContext')
const { selectedComponent, app } = getContext<AppEditorContext>('AppEditorContext')
</script>
{#each $lazyGrid as gridItem (gridItem.data.id)}
{#each $app.grid as gridItem (gridItem.data.id)}
{#if gridItem.data.id === $selectedComponent}
<ComponentPanel bind:component={gridItem.data} />
<ComponentPanel parent={undefined} bind:component={gridItem.data} />
{:else if gridItem.data.type === 'tablecomponent'}
<TablePanel bind:component={gridItem.data} />
{:else if gridItem.data.subGrids}
{#each gridItem.data.subGrids as subGrid}
{#each subGrid as subGridItem, index (subGridItem.data.id)}
{#if subGridItem.data.id === $selectedComponent}
<ComponentPanel
bind:component={subGridItem.data}
onDelete={() => {
subGrid.splice(index, 1)
subGrid = subGrid
}}
/>
{/if}
{/each}
{/each}
{/if}
{/each}
{#if $app.subgrids}
{#each Object.keys($app.subgrids ?? {}) as key (key)}
{#each $app.subgrids[key] as gridItem (gridItem.data.id)}
{#if gridItem.data.id === $selectedComponent}
<ComponentPanel parent={key} bind:component={gridItem.data} />
{:else if gridItem.data.type === 'tablecomponent'}
<TablePanel bind:component={gridItem.data} />
{/if}
{/each}
{/each}
{/if}
{#each $app?.hiddenInlineScripts ?? [] as script, index (script.name)}
{#if $selectedComponent === `bg_${index}`}
<PanelSection title={`Background script inputs`}>

View File

@@ -5,9 +5,13 @@
import { columnConfiguration, isFixed, toggleFixed } from '../gridUtils'
import type { AppEditorContext, GridItem } from '../types'
import Component from './component/Component.svelte'
import { findGridItem } from './appUtils'
export let subGrid: GridItem[]
export let containerHeight: number
export let noPadding = false
//export let id: string
export let subGrid: GridItem[] = []
export let visible: boolean = true
const dispatch = createEventDispatcher()
@@ -35,11 +39,17 @@
onComponent = id
if (!$connectingInput.opened) {
$selectedComponent = id
/*
$focusedGrid = {
parentComponentId: parentId,
subGridIndex: index
}
*/
}
}
function lock(gridComponent: GridItem) {
let fComponent = $app.grid.find((c) => c.id === gridComponent.id)
let fComponent = findGridItem($app, gridComponent.data.id)
if (fComponent) {
fComponent = toggleFixed(fComponent)
}
@@ -47,33 +57,12 @@
// @ts-ignore
let container
$: if ($focusedGrid?.parentComponentId !== $selectedComponent) {
const gridItemIds = $app.grid
.map((gridItem: GridItem) => {
if (gridItem.data.id === $focusedGrid?.parentComponentId) {
const subGrids = gridItem.data.subGrids ?? []
return [
gridItem.data.id,
...subGrids.map((subGrid: GridItem[]) =>
subGrid.map((gridItem: GridItem) => gridItem.data.id)
)
]
} else {
return []
}
})
.flat(2)
if (!gridItemIds.includes($selectedComponent)) {
$focusedGrid = undefined
}
}
</script>
<div class="relative w-full subgrid " bind:this={container}>
<div class="relative w-full subgrid {visible ? 'visible' : 'invisible h-0 '}" bind:this={container}>
<div
class="px-4 pt-4 overflow-auto {$connectingInput?.opened ? '' : ''}"
class:px-2={!noPadding}
class="py-2 overflow-auto {$connectingInput?.opened ? '' : ''}"
on:pointerdown|stopPropagation={onpointerdown}
on:pointerleave={onpointerup}
on:pointerup={onpointerup}
@@ -121,7 +110,7 @@
>
<Component
{pointerdown}
bind:component={gridComponent.data}
bind:pComponent={gridComponent.data}
selected={$selectedComponent === dataItem.data.id}
locked={isFixed(gridComponent)}
on:lock={() => lock(gridComponent)}

View File

@@ -11,6 +11,8 @@
{#each component.actionButtons as actionButton (actionButton.id)}
{#if actionButton.id === $selectedComponent}
<ComponentPanel
parent={undefined}
noGrid
rowColumns
bind:component={actionButton}
onDelete={() => {

View File

@@ -0,0 +1,173 @@
import { getNextId } from '$lib/components/flows/flowStateUtils'
import type { App, FocusedGrid, GridItem } from '../types'
import { getRecommendedDimensionsByComponent, type AppComponent } from './component'
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
import { gridColumns } from '../gridUtils'
import { allItems } from '../utils'
function findGridItemById(
root: GridItem[],
subGrids: Record<string, GridItem[]> | undefined,
id: string
): GridItem | undefined {
for (const gridItem of allItems(root, subGrids)) {
if (gridItem.id === id) {
return gridItem
}
}
return undefined
}
export function findGridItem(app: App, id: string): GridItem | undefined {
return findGridItemById(app.grid, app.subgrids, id)
}
export function getNextGridItemId(app: App): string {
const subgridsKeys = allItems(app.grid, app.subgrids).map((x) => x.id)
const withoutDash = subgridsKeys.map((element) => element.split('-')[0])
const id = getNextId([...new Set(withoutDash)])
return id
}
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
const appComponent = data
appComponent.id = id
const newComponent = {
fixed: false,
resizable: true,
draggable: true,
customDragger: false,
customResizer: false,
x: 0,
y: 0
}
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
const newItem: GridItem = {
data: newData,
id: id
}
gridColumns.forEach((column) => {
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
newItem[column] = {
...newComponent,
min: { w: 1, h: 1 },
max: { w: column, h: 100 },
w: rec.w,
h: rec.h
}
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
newItem[column] = { ...newItem[column], ...position }
})
return newItem
}
export function insertNewGridItem(
app: App,
data: AppComponent,
focusedGrid: FocusedGrid | undefined,
keepId?: boolean
) {
const id = keepId ? data.id : getNextGridItemId(app)
if (!app.subgrids) {
app.subgrids = {}
}
if (!focusedGrid) {
const newItem = createNewGridItem(app.grid, id, data)
app.grid.push(newItem)
} else {
const { parentComponentId, subGridIndex } = focusedGrid
const key = `${parentComponentId}-${subGridIndex ?? 0}`
const subGrid = app.subgrids[key] ?? []
subGrid.push(createNewGridItem(subGrid, id, data))
app.subgrids[key] = subGrid
}
for (let i = 0; i < (data.numberOfSubgrids ?? 0); i++) {
app.subgrids[`${id}-${i}`] = []
}
return id
}
export function getAllSubgridsAndComponentIds(
app: App,
component: AppComponent
): [string[], string[]] {
const subgrids: string[] = []
let components: string[] = [component.id]
if (app.subgrids && component.numberOfSubgrids) {
for (let i = 0; i < component.numberOfSubgrids; i++) {
const key = `${component.id}-${i}`
const subgrid = app.subgrids[key]
if (subgrid) {
subgrids.push(key)
for (const item of subgrid) {
let [recSubgrids, recComponents] = getAllSubgridsAndComponentIds(app, item.data)
subgrids.push(...recSubgrids)
components.push(...recComponents)
}
}
}
}
return [subgrids, components]
}
export function deleteGridItem(
app: App,
component: AppComponent,
parent: string | undefined
): string[] {
let [subgrids, components] = getAllSubgridsAndComponentIds(app, component)
if (app.subgrids) {
subgrids.forEach((id) => {
delete app.subgrids![id]
})
}
if (!parent) {
let index = app.grid.findIndex((x) => x.id == component.id)
if (index > -1) {
app.grid.splice(index, 1)
}
} else {
let grid = app.subgrids![parent]
let index = grid.findIndex((x) => x.id == component.id)
if (index > -1) {
grid.splice(index, 1)
}
}
return components
}
export function duplicateGridItem(
app: App,
parent: string | undefined,
id: string
): string | undefined {
const gridItem = findGridItem(app, id)
if (gridItem) {
const newId = getNextGridItemId(app)
const newItem = JSON.parse(JSON.stringify(gridItem))
newItem.id = newId
newItem.data.id = newId
let focusedGrid = parent
? { parentComponentId: parent.split('-')[0], subGridIndex: Number(parent.split('-')[1]) }
: undefined
return insertNewGridItem(app, newItem.data, focusedGrid)
}
return undefined
}

View File

@@ -5,6 +5,8 @@
import { twMerge } from 'tailwind-merge'
import type { AppEditorContext } from '../../types'
import ComponentHeader from '../ComponentHeader.svelte'
import { deepEqual } from 'fast-equals'
import {
AppBarChart,
AppDisplayComponent,
@@ -35,8 +37,9 @@
AppContainer
} from '../../components'
import type { AppComponent } from './components'
import AppAggridTable from '../../components/display/table/AppAggridTable.svelte'
export let component: AppComponent
export let pComponent: AppComponent
export let selected: boolean
export let locked: boolean = false
export let pointerdown: boolean = false
@@ -46,6 +49,11 @@
let hover = false
let initializing: boolean | undefined = undefined
let componentContainerHeight: number = 0
let component = JSON.parse(JSON.stringify(pComponent))
$: if (pComponent && !deepEqual(pComponent, component)) {
component = JSON.parse(JSON.stringify(pComponent))
}
</script>
<div
@@ -143,6 +151,13 @@
bind:componentInput={component.componentInput}
bind:actionButtons={component.actionButtons}
/>
{:else if component.type === 'aggridcomponent'}
<AppAggridTable
{...component}
bind:initializing
bind:staticOutputs={$staticOutputs[component.id]}
bind:componentInput={component.componentInput}
/>
{:else if component.type === 'textcomponent'}
<AppText
{...component}

View File

@@ -63,6 +63,7 @@ export type ScatterChartComponent = BaseComponent<'scatterchartcomponent'>
export type TableComponent = BaseComponent<'tablecomponent'> & {
actionButtons: (BaseAppComponent & ButtonComponent)[]
}
export type AggridComponent = BaseComponent<'aggridcomponent'>
export type DisplayComponent = BaseComponent<'displaycomponent'>
export type ImageComponent = BaseComponent<'imagecomponent'>
export type InputComponent = BaseComponent<'inputcomponent'>
@@ -73,7 +74,9 @@ export type IconComponent = BaseComponent<'iconcomponent'>
export type HorizontalDividerComponent = BaseComponent<'horizontaldividercomponent'>
export type VerticalDividerComponent = BaseComponent<'verticaldividercomponent'>
export type FileInputComponent = BaseComponent<'fileinputcomponent'>
export type TabsComponent = BaseComponent<'tabscomponent'>
export type TabsComponent = BaseComponent<'tabscomponent'> & {
tabs: string[]
}
export type ContainerComponent = BaseComponent<'containercomponent'>
export type AppComponent = BaseAppComponent &
@@ -108,6 +111,7 @@ export type AppComponent = BaseAppComponent &
| VerticalDividerComponent
| FileInputComponent
| ImageComponent
| AggridComponent
)
export type AppComponentDimensions = `${IntRange<
@@ -150,7 +154,7 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
configuration: {},
customCss: {
header: { class: '', style: '' },
container: { class: '', style: '' },
container: { class: '', style: '' }
} as const,
card: false
}
@@ -161,18 +165,19 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
dims: '2:8-6:8',
data: {
softWrap: true,
verticalAlignment: 'center',
id: '',
type: 'containercomponent',
configuration: {},
componentInput: {
type: 'static',
fieldType: 'array',
subFieldType: 'text',
value: ['First Tab', 'Second Tab']
configuration: {
noPadding: {
type: 'static',
fieldType: 'boolean',
value: false,
onlyStatic: true
}
},
componentInput: undefined,
card: false,
subGrids: [[]]
numberOfSubgrids: 1
}
},
textcomponent: {
@@ -691,6 +696,48 @@ Hello \${ctx.username}
actionButtons: []
}
},
aggridcomponent: {
name: 'AgGrid Table',
icon: Table2,
dims: '3:10-6:10',
data: {
id: '',
type: 'aggridcomponent',
configuration: {
columnDefs: {
type: 'static',
fieldType: 'array',
subFieldType: 'object',
value: [{ field: 'id' }, { field: 'name', editable: true }, { field: 'age' }]
},
allEditable: {
type: 'static',
fieldType: 'boolean',
value: false,
onlyStatic: true
}
},
componentInput: {
type: 'static',
fieldType: 'array',
subFieldType: 'object',
value: [
{
id: 1,
name: 'A cell with a long name',
age: 42
},
{
id: 2,
name: 'A briefer cell',
age: 84
}
]
},
customCss: {},
card: true,
}
},
checkboxcomponent: {
name: 'Toggle',
icon: ToggleLeft,
@@ -807,19 +854,16 @@ Hello \${ctx.username}
type: 'static',
value: undefined,
fieldType: 'number',
onlyStatic: true
},
max: {
type: 'static',
value: undefined,
fieldType: 'number',
onlyStatic: true
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
onlyStatic: true
}
},
customCss: {},
@@ -888,19 +932,16 @@ Hello \${ctx.username}
type: 'static',
value: 42,
fieldType: 'number',
onlyStatic: true
},
defaultValue: {
type: 'static',
value: 20,
fieldType: 'number',
onlyStatic: true
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
onlyStatic: true
}
},
customCss: {},
@@ -922,31 +963,26 @@ Hello \${ctx.username}
type: 'static',
value: 0,
fieldType: 'number',
onlyStatic: true
},
max: {
type: 'static',
value: 42,
fieldType: 'number',
onlyStatic: true
},
defaultLow: {
type: 'static',
value: 10,
fieldType: 'number',
onlyStatic: true
},
defaultHigh: {
type: 'static',
value: 20,
fieldType: 'number',
onlyStatic: true
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
onlyStatic: true
}
},
customCss: {},
@@ -1012,18 +1048,20 @@ Hello \${ctx.username}
dims: '2:8-6:8',
data: {
softWrap: true,
verticalAlignment: 'center',
id: '',
type: 'tabscomponent',
configuration: {},
componentInput: {
type: 'static',
fieldType: 'array',
subFieldType: 'text',
value: ['First Tab', 'Second Tab']
configuration: {
noPadding: {
type: 'static',
fieldType: 'boolean',
value: false,
onlyStatic: true
}
},
componentInput: undefined,
card: false,
subGrids: [[], []]
numberOfSubgrids: 2,
tabs: ['First tab', 'Second tab']
}
},
iconcomponent: {
@@ -1195,4 +1233,4 @@ Hello \${ctx.username}
card: false
}
}
}
}

View File

@@ -39,6 +39,7 @@ const display: ComponentSet = {
'imagecomponent',
'htmlcomponent',
'tablecomponent',
'aggridcomponent',
'barchartcomponent',
'piechartcomponent',
'vegalitecomponent',

View File

@@ -1,34 +1,20 @@
<script lang="ts">
import type { AppEditorContext, GridItem } from '../../types'
import type { AppEditorContext } from '../../types'
import { getContext, onMount } from 'svelte'
import { getNextId } from '$lib/components/flows/flowStateUtils'
import { isOpenStore } from './store'
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
import { components as componentsRecord, COMPONENT_SETS, type AppComponent } from '../component'
import ListItem from './ListItem.svelte'
import { insertNewGridItem, createNewGridItem, getNextGridItemId } from '../../utils'
import { insertNewGridItem } from '../appUtils'
const TITLE_PREFIX = 'Component.' as const
const { app, selectedComponent, focusedGrid } = getContext<AppEditorContext>('AppEditorContext')
function addComponent(appComponentType: AppComponent['type']): void {
// When a new component is added, we need to mark the app as dirty,
// so a confirmation modal will appear if the user tries to leave the page
$dirtyStore = true
const grid = $app.grid ?? []
const id = getNextGridItemId(grid)
const data = componentsRecord[appComponentType].data
if ($focusedGrid) {
const { parentComponentId, subGridIndex } = $focusedGrid
$app.grid = insertNewGridItem($app.grid, parentComponentId, subGridIndex, id, data)
} else {
const newItem = createNewGridItem(grid, id, data)
$app.grid = [...grid, newItem]
}
const id = insertNewGridItem($app, data, $focusedGrid)
$selectedComponent = id
}

View File

@@ -2,6 +2,7 @@
import { classNames } from '$lib/utils'
import { getContext } from 'svelte'
import type { AppEditorContext } from '../../types'
import { findGridItem } from '../appUtils'
import { components } from '../component'
import PanelSection from '../settingsPanel/common/PanelSection.svelte'
import ComponentOutputViewer from './ComponentOutputViewer.svelte'
@@ -26,7 +27,7 @@
}
function getComponentNameById(componentId: string) {
const component = $app.grid.find((c) => c?.data?.id === componentId)
const component = findGridItem($app, componentId)
if (component?.data.type) {
return components[component?.data.type].name

View File

@@ -164,13 +164,13 @@
createInlineScriptByLanguage(Script.language.DENO, name, 'pgsql')
}}
/>
<FlowScriptPicker
<!-- <FlowScriptPicker
label={`MySQL`}
lang="mysql"
on:click={() => {
createInlineScriptByLanguage(Script.language.DENO, name, 'mysql')
}}
/>
/> -->
</div>
<div class="mt-4">

View File

@@ -8,10 +8,11 @@
import { emptySchema, getScriptByPath } from '$lib/utils'
import { faCodeBranch, faExternalLinkAlt, faEye, faPen } from '@fortawesome/free-solid-svg-icons'
import type { AppInput, RunnableByPath } from '../../inputType'
import { clearResultAppInput, schemaToInputsSpec } from '../../utils'
import { clearResultAppInput } from '../../utils'
import EmptyInlineScript from './EmptyInlineScript.svelte'
import InlineScriptEditor from './InlineScriptEditor.svelte'
import { computeFields } from './utils'
import { deepEqual } from 'fast-equals'
export let componentInput: AppInput | undefined
export let id: string
@@ -43,7 +44,7 @@
async function refreshScript(x: RunnableByPath) {
let { schema } = await getScriptByPath(x.path)
if (JSON.stringify(x.schema) != JSON.stringify(schema)) {
if (!deepEqual(x.schema, schema)) {
x.schema = schema
if (componentInput?.type == 'runnable') {
componentInput.fields = computeFields(schema, false, componentInput.fields)

View File

@@ -4,11 +4,11 @@
import SplitPanesWrapper from '$lib/components/splitPanes/SplitPanesWrapper.svelte'
import { Pane, Splitpanes } from 'svelte-splitpanes'
import InlineScriptsPanelList from './InlineScriptsPanelList.svelte'
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
import InlineScriptEditor from './InlineScriptEditor.svelte'
import EmptyInlineScript from './EmptyInlineScript.svelte'
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
const { lazyGrid, app, staticOutputs, runnableComponents } =
const { app, staticOutputs, runnableComponents } =
getContext<AppEditorContext>('AppEditorContext')
let selectedScriptComponentId: string | undefined = undefined
@@ -23,16 +23,17 @@
{#if !selectedScriptComponentId}
<span class="p-2 text-sm text-gray-600">Select a script on the left panel</span>
{/if}
{#each $lazyGrid as gridComponent, index (index)}
{#if gridComponent.data.id === selectedScriptComponentId}
{#each $app.grid as gridItem (gridItem.data.id)}
{#if gridItem.data.id === selectedScriptComponentId}
<InlineScriptEditorPanel
id={gridComponent.data.id}
bind:componentInput={gridComponent.data.componentInput}
id={gridItem.data.id}
bind:componentInput={gridItem.data.componentInput}
/>
{/if}
{#if gridComponent.data.type === 'tablecomponent'}
{#each gridComponent.data.actionButtons as actionButton, index (index)}
{#if gridItem.data.type === 'tablecomponent'}
{#each gridItem.data.actionButtons as actionButton, index (index)}
{#if actionButton.id === selectedScriptComponentId}
<InlineScriptEditorPanel
id={actionButton.id}
@@ -42,6 +43,31 @@
{/each}
{/if}
{/each}
{#if $app.subgrids}
{#each Object.keys($app.subgrids ?? {}) as key (key)}
{#each $app.subgrids[key] as gridItem (gridItem.data.id)}
{#if gridItem.data.id === selectedScriptComponentId}
<InlineScriptEditorPanel
id={gridItem.data.id}
bind:componentInput={gridItem.data.componentInput}
/>
{/if}
{#if gridItem.data.type === 'tablecomponent'}
{#each gridItem.data.actionButtons as actionButton, index (index)}
{#if actionButton.id === selectedScriptComponentId}
<InlineScriptEditorPanel
id={actionButton.id}
bind:componentInput={actionButton.componentInput}
/>
{/if}
{/each}
{/if}
{/each}
{/each}
{/if}
{#each $app.unusedInlineScripts as unusedInlineScript, index (index)}
{#if `unused-${index}` === selectedScriptComponentId}
<InlineScriptEditor

View File

@@ -21,7 +21,7 @@
}
}
$: runnables = getAppScripts($lazyGrid)
$: runnables = getAppScripts($lazyGrid, $app.subgrids)
// When selected component changes, update selectedScriptComponentId
$: if ($selectedComponent != selectedScriptComponentId) {

View File

@@ -1,11 +1,11 @@
import type { Schema } from "$lib/common";
import type { AppInputs, Runnable } from "../../inputType"
import type { GridItem } from "../../types"
import { fieldTypeToTsType, schemaToInputsSpec } from "../../utils";
import type { AppComponent } from "../component";
import type { Schema } from '$lib/common'
import type { AppInputs, Runnable } from '../../inputType'
import type { GridItem } from '../../types'
import { fieldTypeToTsType, schemaToInputsSpec } from '../../utils'
import type { AppComponent } from '../component'
export interface AppScriptsList {
inline: { name: string; id: string }[],
inline: { name: string; id: string }[]
imported: { name: string; id: string }[]
}
@@ -42,38 +42,50 @@ export function computeFields(schema: Schema, defaultUserInput: boolean, fields:
return result
}
export function getAppScripts(grid: GridItem[]) {
return grid.reduce((acc, gridComponent) => {
const component: AppComponent = gridComponent.data
const componentInput = component.componentInput
function processGridItemRunnable(gridItem: GridItem, list: AppScriptsList): AppScriptsList {
const component: AppComponent = gridItem.data
const componentInput = component.componentInput
if (component.type === 'tablecomponent') {
component.actionButtons.forEach((actionButton) => {
if (actionButton.componentInput?.type !== 'runnable') {
return
}
processRunnable(actionButton.componentInput.runnable, actionButton.id, list)
})
}
if (componentInput?.type === 'runnable') {
processRunnable(componentInput.runnable, gridItem.id, list)
}
return list
}
if (component.type === 'tablecomponent') {
component.actionButtons.forEach((actionButton) => {
if (actionButton.componentInput?.type !== 'runnable') { return }
processRunnable(
actionButton.componentInput.runnable,
actionButton.id,
acc
)
export function getAppScripts(
lazyGrid: GridItem[],
subgrids: Record<string, GridItem[]> | undefined
): AppScriptsList {
const scriptsList = lazyGrid.reduce(
(acc, gridComponent) => processGridItemRunnable(gridComponent, acc),
{ inline: [], imported: [] } as AppScriptsList
)
if (subgrids) {
Object.values(subgrids).forEach((subgrid: GridItem[]) => {
subgrid.forEach((subgridComponent: GridItem) => {
processGridItemRunnable(subgridComponent, scriptsList)
})
}
if (componentInput?.type === 'runnable') {
processRunnable(
componentInput.runnable,
gridComponent.id,
acc
)
}
})
}
return acc
}, { inline: [], imported: [] } as AppScriptsList)
return scriptsList
}
function processRunnable(runnable: Runnable, id: string, list: AppScriptsList) {
if (runnable?.type === undefined) { return }
if (runnable?.type === undefined) {
return
}
const type: keyof AppScriptsList = runnable.type === 'runnableByPath' ? 'imported' : 'inline'
list[type].push({
name: runnable[runnable.type === 'runnableByPath' ? 'path' : 'name'],
id
})
}
}

View File

@@ -2,7 +2,7 @@
import Button from '$lib/components/common/button/Button.svelte'
import { faCopy, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { getContext } from 'svelte'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, GridItem } from '../../types'
import PanelSection from './common/PanelSection.svelte'
import InputsSpecsEditor from './InputsSpecsEditor.svelte'
import TableActions from './TableActions.svelte'
@@ -10,14 +10,7 @@
import ConnectedInputEditor from './inputEditor/ConnectedInputEditor.svelte'
import Badge from '$lib/components/common/badge/Badge.svelte'
import { capitalize, classNames } from '$lib/utils'
import {
buildExtraLib,
createNewGridItem,
fieldTypeToTsType,
findParent,
getNextGridItemId,
insertNewGridItem
} from '../../utils'
import { buildExtraLib, fieldTypeToTsType } from '../../utils'
import Recompute from './Recompute.svelte'
import Tooltip from '$lib/components/Tooltip.svelte'
import ComponentInputTypeEditor from './ComponentInputTypeEditor.svelte'
@@ -27,81 +20,44 @@
import type { AppComponent } from '../component'
import CssProperty from '../componentsPanel/CssProperty.svelte'
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
import GridTab from './GridTab.svelte'
import { duplicateGridItem } from '../appUtils'
import { deleteGridItem } from '../appUtils'
import MoveToOtherGrid from './MoveToOtherGrid.svelte'
export let component: AppComponent | undefined
export let onDelete: (() => void) | undefined = undefined
export let component: AppComponent
export let rowColumns = false
export let onDelete: (() => void) | undefined = undefined
export let parent: string | undefined
export let noGrid = false
const { app, staticOutputs, runnableComponents, selectedComponent, worldStore, focusedGrid } =
getContext<AppEditorContext>('AppEditorContext')
function duplicateElement(id: string) {
const parent = findParent($app.grid, id)
if (!parent) {
return
}
const data: AppComponent = JSON.parse(JSON.stringify(parent.data))
$dirtyStore = true
const grid = $app.grid ?? []
const newId = getNextGridItemId(grid)
if ($focusedGrid) {
const { parentComponentId, subGridIndex } = $focusedGrid
$app.grid = insertNewGridItem($app.grid, parentComponentId, subGridIndex, newId, data)
} else {
const newItem = createNewGridItem(grid, newId, data)
$app.grid = [...grid, newItem]
}
const newId = duplicateGridItem($app, parent, id)
$selectedComponent = newId
}
function removeGridElement() {
$selectedComponent = undefined
if (onDelete && component) {
delete $staticOutputs[component.id]
$staticOutputs = $staticOutputs
delete $runnableComponents[component.id]
$runnableComponents = $runnableComponents
onDelete()
// Delete static inputs
} else {
if (component) {
$app.grid = $app.grid.filter((gridComponent) => gridComponent.data.id !== component?.id)
// Delete static inputs
delete $staticOutputs[component.id]
$staticOutputs = $staticOutputs
delete $runnableComponents[component.id]
$runnableComponents = $runnableComponents
$focusedGrid = undefined
if (component && !noGrid) {
let ids = deleteGridItem($app, component, parent)
for (const key of ids) {
delete $staticOutputs[key]
delete $runnableComponents[key]
}
}
if (
component &&
component.componentInput?.type === 'runnable' &&
component.componentInput?.runnable?.type === 'runnableByName'
) {
const { name, inlineScript } = component.componentInput.runnable
delete $staticOutputs[component.id]
delete $runnableComponents[component.id]
$app = $app
$staticOutputs = $staticOutputs
$runnableComponents = $runnableComponents
if (inlineScript) {
if (!$app.unusedInlineScripts) {
$app.unusedInlineScripts = []
}
$app.unusedInlineScripts.push({
name,
inlineScript
})
}
}
onDelete?.()
}
$: extraLib =
@@ -140,18 +96,7 @@
<div class="flex flex-col w-full gap-2 my-2">
{#if component.componentInput.type === 'static'}
<StaticInputEditor
bind:componentInput={component.componentInput}
on:deleteArrayItem={(e) => {
if (component?.type === 'tabscomponent') {
const deletedIndex = e.detail.index
if (component.subGrids) {
component.subGrids.splice(deletedIndex, 1)
}
}
}}
/>
<StaticInputEditor bind:componentInput={component.componentInput} />
{:else if component.componentInput.type === 'template' && component.componentInput !== undefined}
<div class="py-1 min-h-[28px] rounded border border-1 border-gray-500">
<TemplateEditor fontSize={12} bind:code={component.componentInput.eval} {extraLib} />
@@ -204,6 +149,10 @@
</PanelSection>
{/if}
{#if component.type === 'tabscomponent'}
<GridTab bind:tabs={component.tabs} {component} />
{/if}
{#if component.type === 'tablecomponent' && Array.isArray(component.actionButtons)}
<TableActions id={component.id} bind:components={component.actionButtons} />
{/if}
@@ -228,8 +177,7 @@
<PanelSection title="Duplicate">
<Button
size="xs"
color="blue"
variant="border"
color="dark"
startIcon={{ icon: faCopy }}
on:click={() => {
if (component) {
@@ -241,6 +189,10 @@
</Button>
</PanelSection>
<PanelSection title="Move to other grid">
<MoveToOtherGrid bind:component {parent} />
</PanelSection>
<PanelSection title="Danger zone">
<Button
size="xs"

View File

@@ -0,0 +1,83 @@
<script lang="ts">
import Button from '$lib/components/common/button/Button.svelte'
import { faPlus, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { getContext } from 'svelte'
import type { AppEditorContext } from '../../types'
import { deleteGridItem } from '../appUtils'
import type { AppComponent } from '../component'
import PanelSection from './common/PanelSection.svelte'
export let tabs: string[]
export let component: AppComponent
const { app, staticOutputs, runnableComponents } =
getContext<AppEditorContext>('AppEditorContext')
function addTab() {
const numberOfTabs = tabs.length
tabs = [...tabs, `Tab ${numberOfTabs + 1}`]
if (!$app.subgrids) {
$app.subgrids = {}
}
$app.subgrids[`${component.id}-${numberOfTabs}`] = []
component.numberOfSubgrids = tabs.length
}
function deleteSubgrid(index: number) {
let subgrid = `${component.id}-${index}`
for (const item of $app!.subgrids![subgrid]) {
const components = deleteGridItem($app, item.data, subgrid)
console.log(components)
for (const key in components) {
delete $staticOutputs[key]
delete $runnableComponents[key]
}
}
$staticOutputs = $staticOutputs
$runnableComponents = $runnableComponents
for (let i = index; i < tabs.length - 1; i++) {
$app!.subgrids![`${component.id}-${i}`] = $app!.subgrids![`${component.id}-${i + 1}`]
}
tabs.splice(index, 1)
tabs = tabs
component.numberOfSubgrids = tabs.length
$app = $app
}
</script>
<PanelSection title={`Tabs ${tabs.length > 0 ? `(${tabs.length})` : ''}`}>
{#if tabs.length == 0}
<span class="text-xs text-gray-500">No Tabs</span>
{/if}
<div class="flex gap-2 flex-col mt-2">
{#each tabs as value, index (index)}
<div class="flex flex-row gap-2 items-center relative">
<input type="text" bind:value />
<div class="absolute top-1 right-1">
<Button
size="xs"
color="light"
variant="border"
on:click={() => {
deleteSubgrid(index)
}}
iconOnly
btnClasses="!text-red-500"
startIcon={{ icon: faTrashAlt }}
/>
</div>
</div>
{/each}
<Button
size="xs"
color="light"
variant="border"
startIcon={{ icon: faPlus }}
on:click={addTab}
iconOnly
/>
</div>
</PanelSection>

View File

@@ -0,0 +1,117 @@
<script lang="ts">
import { Button } from '$lib/components/common'
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
import { faCopy } from '@fortawesome/free-solid-svg-icons'
import { getContext } from 'svelte'
import type { App, AppEditorContext } from '../../types'
import {
createNewGridItem,
deleteGridItem,
findGridItem,
getAllSubgridsAndComponentIds,
insertNewGridItem
} from '../appUtils'
import type { AppComponent } from '../component'
export let component: AppComponent | undefined
export let parent: string | undefined
let selectedOption: string
const { app } = getContext<AppEditorContext>('AppEditorContext')
function listAllSubGrids(app: App) {
return app.subgrids ? Object.keys(app.subgrids) : []
}
function findAndDelete(id: string) {
const node = findGridItem($app, id)
if (!node) {
return
}
const data: AppComponent = JSON.parse(JSON.stringify(node.data))
$dirtyStore = true
deleteGridItem($app, data, parent)
return data
}
function insertComponentInSubGrid(
data: AppComponent,
targetId: string,
targetSubGridIndex: number
) {
insertNewGridItem(
$app,
data,
{
parentComponentId: targetId,
subGridIndex: targetSubGridIndex
},
true
)
$app.grid = [...$app.grid]
}
function insertComponentInMainGrid(data: AppComponent) {
const newComponent = createNewGridItem($app.grid, data.id, data)
$app.grid = [...$app.grid, newComponent]
}
function onMove(component: AppComponent) {
const data = findAndDelete(component.id)
if (!data) {
return
}
if (selectedOption !== 'main-grid') {
const [targetId, targetSubGridIndex] = selectedOption.split('-')
insertComponentInSubGrid(data, targetId, parseInt(targetSubGridIndex))
} else {
insertComponentInMainGrid(data)
}
}
const defaultOption = {
label: 'Main grid',
value: 'main-grid',
disabled: parent === undefined
}
$: [subgrids] = component ? getAllSubgridsAndComponentIds($app, component) : [[], []]
$: availableGrids = listAllSubGrids($app)
$: options = availableGrids
? [
defaultOption,
...availableGrids?.map((grid) => ({
label: grid,
value: grid,
disabled: grid === parent || subgrids.includes(grid)
}))
]
: [defaultOption]
</script>
{#if component && !options.every((option) => option.disabled)}
<select bind:value={selectedOption} class="w-full">
{#each options as option}
<option value={option.value} disabled={option.disabled}>{option.label}</option>
{/each}
</select>
<Button
size="xs"
color="dark"
startIcon={{ icon: faCopy }}
on:click={() => {
if (component) {
onMove(component)
}
}}
>
Move component: {component.id}
</Button>
{:else}
<p class="text-gray-500 text-sm">No grids available</p>
{/if}

View File

@@ -95,17 +95,28 @@
}}
on:keypress
>
<Badge color="dark-indigo">
{component.id}
</Badge>
<div>
<TableActionLabel componentInput={component.configuration.label} />
</div>
<div>
<Button variant="border" color="red" on:click={() => deleteComponent(component.id)}>
<Icon class="h-3" data={faTrashAlt} />
</Button>
</div>
<div>
<TableActionLabel componentInput={component.configuration.label} />
</div>
<Badge color="dark-indigo">
{component.id}
</Badge>
</div>
{/each}
<div class="w-full">
<Button
btnClasses="w-full"
color="light"
variant="border"
startIcon={{ icon: faPlus }}
on:click={addComponent}
iconOnly
/>
</div>
</PanelSection>

View File

@@ -59,7 +59,8 @@ export interface BaseAppComponent extends Partial<Aligned> {
* *For example when the component has a popup like `Select`*
*/
softWrap?: boolean
subGrids?: GridItem[][]
// Number of subgrids
numberOfSubgrids?: number
}
export type ComponentSet = {
@@ -99,6 +100,7 @@ export type App = {
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
}>
css?: Record<'viewer' | 'grid' | AppComponent['type'], ComponentCustomCSS>
subgrids?: Record<string, GridItem[]>
}
export type ConnectingInput = {
@@ -132,7 +134,6 @@ export type AppEditorContext = {
}
export type FocusedGrid = { parentComponentId: string; subGridIndex: number }
export type EditorMode = 'dnd' | 'preview'
export type EditorBreakpoint = 'sm' | 'lg'

View File

@@ -2,19 +2,74 @@ import type { Schema } from '$lib/common'
import { FlowService, ScriptService } from '$lib/gen'
import { inferArgs } from '$lib/infer'
import { emptySchema } from '$lib/utils'
import type { AppComponent, AppComponentConfig } from './editor/component'
import {
components as componentsRecord,
getRecommendedDimensionsByComponent
} from './editor/component'
import { gridColumns } from './gridUtils'
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
import type { AppComponent } from './editor/component'
import type { AppInput, InputType, ResultAppInput, StaticAppInput } from './inputType'
import type { Output } from './rx'
import type { App, GridItem } from './types'
import { getNextId } from '../flows/flowStateUtils'
/*
export function deleteComponent(
subgrid: string | undefined,
component: AppComponent,
app: App,
staticOutputs: Record<string, any>,
runnableComponents: Record<string, any>
) {
if (parentItems) {
let index = parentItems.findIndex((item) => item.data?.id === component.id)
if (index != -1) {
parentItems.splice(index, 1)
}
}
delete staticOutputs[component.id]
delete runnableComponents[component.id]
if (
component.componentInput?.type === 'runnable' &&
component.componentInput?.runnable?.type === 'runnableByName'
) {
const { name, inlineScript } = component.componentInput.runnable
if (inlineScript) {
if (!app.unusedInlineScripts) {
app.unusedInlineScripts = []
}
app.unusedInlineScripts.push({
name,
inlineScript
})
}
}
}
*/
export function allItems(
grid: GridItem[],
subgrids: Record<string, GridItem[]> | undefined
): GridItem[] {
if (subgrids == undefined) {
return grid
}
return [...grid, ...Object.values(subgrids).flat()]
}
export function allItemsWithParent(
grid: GridItem[],
subgrids: Record<string, GridItem[]> | undefined
): [GridItem, string | undefined][] {
const items: [GridItem, string | undefined][] = grid.map((item) => [item, undefined])
if (subgrids == undefined) {
return items
}
return [
...items,
...Object.entries(subgrids).flatMap(([k, v]) => v.map((g) => [g, k] as [GridItem, string]))
]
}
export async function loadSchema(
workspace: string,
@@ -218,101 +273,3 @@ export function toPascalCase(text: string) {
export function toKebabCase(text: string) {
return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
}
export function findParent(root: GridItem[], id: string): GridItem | undefined {
for (const a of root) {
if (a.id === id) {
return a
}
if (a.data.subGrids) {
// Recursively search the sub-grids
for (const subGrid of a.data.subGrids) {
const result = findParent(subGrid, id)
if (result) {
return result
}
}
}
}
return undefined
}
export function insertNewGridItem(
root: GridItem[],
id: string,
subGridIndex: number,
newId: string,
data: AppComponent
): GridItem[] {
const parentA = findParent(root, id)
if (!parentA) {
throw new Error(`Parent A object with ID ${id} not found.`)
}
const subGrid = parentA.data.subGrids[subGridIndex]
if (!subGrid) {
throw new Error(`Sub-grid with index ${subGridIndex} not found.`)
}
const newItem = createNewGridItem(subGrid ?? [], newId, data)
subGrid.push(newItem)
return root
}
// The grid is needed to find a space for the new component
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
const appComponent = data
appComponent.id = id
const newComponent = {
fixed: false,
resizable: true,
draggable: true,
customDragger: false,
customResizer: false,
x: 0,
y: 0
}
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
const newItem: GridItem = {
data: newData,
id: id
}
gridColumns.forEach((column) => {
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
newItem[column] = {
...newComponent,
min: { w: 1, h: 1 },
max: { w: column, h: 100 },
w: rec.w,
h: rec.h
}
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
newItem[column] = { ...newItem[column], ...position }
})
return newItem
}
function recursiveGetIds(gridItem: GridItem): string[] {
const subGrids = gridItem.data.subGrids ?? []
const subGridIds = subGrids
.map((subGrid: GridItem[]) => subGrid.map(recursiveGetIds))
.flat(Infinity)
return [gridItem.data.id, ...subGridIds]
}
export function getNextGridItemId(grid: GridItem[] = []): string {
const gridItemIds = grid.map(recursiveGetIds).flat()
const id = getNextId(gridItemIds)
return id
}

View File

@@ -29,6 +29,11 @@
const dispatch = createEventDispatcher()
// Order of classes: border, border modifier, bg, bg modifier, text, text modifier, everything else
const colorVariants: Record<ButtonType.Color, Record<ButtonType.Variant, string>> = {
none: {
border: '',
contained: ''
},
blue: {
border:
'border-frost-500 hover:border-frost-700 focus:border-frost-700 bg-white hover:bg-frost-100 focus:bg-frost-100 text-frost-500 hover:text-frost-700 focus:text-frost-700 focus:ring-frost-300',

View File

@@ -1,4 +1,4 @@
export const BUTTON_COLORS = ['blue', 'red', 'dark', 'light', 'green', 'gray'] as const
export const BUTTON_COLORS = ['blue', 'red', 'dark', 'light', 'green', 'gray', 'none'] as const
export namespace ButtonType {

View File

@@ -142,12 +142,12 @@
dispatch('new', { language: RawScript.language.DENO, kind, subkind: 'pgsql' })}
/>
<FlowScriptPicker
<!-- <FlowScriptPicker
label={`MySQL`}
lang="mysql"
on:click={() =>
dispatch('new', { language: RawScript.language.DENO, kind, subkind: 'mysql' })}
/>
/> -->
{/if}
{/if}
</div>

View File

@@ -22,6 +22,7 @@
import FlowModuleSuspend from './FlowModuleSuspend.svelte'
import FlowRetries from './FlowRetries.svelte'
import { getStepPropPicker } from '../previousResults'
import { deepEqual } from 'fast-equals'
import Button from '$lib/components/common/button/Button.svelte'
import Alert from '$lib/components/common/alert/Alert.svelte'
@@ -87,12 +88,12 @@
const { input_transforms, schema } = await loadSchemaFromModule(flowModule)
validCode = true
setTimeout(() => {
if (JSON.stringify(value.input_transforms) !== JSON.stringify(input_transforms)) {
if (!deepEqual(value.input_transforms, input_transforms)) {
inputTransforms = input_transforms
}
})
if (JSON.stringify(schema) !== JSON.stringify($flowStateStore[flowModule.id]?.schema)) {
if (!deepEqual(schema, $flowStateStore[flowModule.id]?.schema)) {
if (!$flowStateStore[flowModule.id]) {
$flowStateStore[flowModule.id] = { schema }
} else {

View File

@@ -42,12 +42,7 @@
<svelte:fragment slot="content">
<TabContent value="settings-metadata" class="p-4 h-full">
<div class="overflow-auto h-full">
<Path
bind:path={$flowStore.path}
{initialPath}
namePlaceholder="my_flow"
kind="flow"
/>
<Path bind:path={$flowStore.path} {initialPath} namePlaceholder="flow" kind="flow" />
<label class="block my-4">
<span class="text-gray-700 text-sm">Summary <Required required={false} /></span>

View File

@@ -234,8 +234,9 @@
inline: ''
}
const wrapperWidth = lang ? 'w-[calc(100%-70px)]' : 'w-[calc(100%-50px)]'
let nodeId = id ?? numberToChars(idGenerator.next().value - 1)
let generatedId = idGenerator.next().value
let nodeId = id ?? numberToChars(generatedId - 1)
// console.log(id, generatedId, nodeId, charsToNumber(nodeId))
return {
id: charsToNumber(nodeId),
position: { x: -1, y: -1 },
@@ -376,6 +377,7 @@
}
function layoutNodes(nodes: Node[]): { nodes: Node[]; height: number } {
// console.log('layoutNodes', nodes)
const stratify = dagStratify().id(({ id }: Node) => numberToChars(id))
const dag = stratify(nodes)
@@ -401,7 +403,6 @@
const edges: Edge[] = []
nodes.forEach((node) => {
node.parentIds.forEach((pid, i) => {
console.log(charsToNumber(pid), pid)
// skip virtual nodes such as collect result
if (errorHandlers[pid] && node.id < 900 && nodes.find((x) => x.id == errorHandlers[pid])) {
edges.push({

View File

@@ -0,0 +1,962 @@
const adjectives = ["abundant",
"accessible",
"accommodative",
"accomplished",
"accurate",
"achievable",
"adaptable",
"adaptive",
"adequate",
"adjustable",
"admirable",
"admiring",
"adorable",
"adored",
"adoring",
"adroit",
"adulatory",
"advanced",
"advantageous",
"adventuresome",
"adventurous",
"affable",
"affectionate",
"affirmative",
"affluent",
"affordable",
"agile",
"agreeable",
"alluring",
"altruistic",
"amazed",
"amazing",
"ambitious",
"amenable",
"amiable",
"amicable",
"ample",
"amusing",
"angelic",
"appealing",
"appreciable",
"appreciated",
"appreciative",
"appropriate",
"ardent",
"articulate",
"artistic",
"assuring",
"astonished",
"astonishing",
"astounded",
"astounding",
"athletic",
"attentive",
"attractive",
"audible",
"auspicious",
"authentic",
"authoritative",
"autonomous",
"available",
"avid",
"awed",
"awesome",
"awestruck",
"balanced",
"beauteous",
"beautiful",
"believable",
"beloved",
"beneficent",
"beneficial",
"beneficiary",
"benevolent",
"best",
"best_known",
"best_performing",
"best_selling",
"better",
"better_known",
"better_than_expected",
"blameless",
"blissful",
"blithe",
"bonny",
"booming",
"boundless",
"bountiful",
"brainiest",
"brainy",
"brand_new",
"brave",
"breathtaking",
"bright",
"brighter",
"brightest",
"brilliant",
"brisk",
"brotherly",
"bullish",
"buoyant",
"calm",
"calming",
"capable",
"captivating",
"carefree",
"catchy",
"celebrated",
"celebratory",
"champion",
"charismatic",
"charitable",
"charming",
"chaste",
"cheaper",
"cheapest",
"cheerful",
"cheery",
"cherished",
"chivalrous",
"classic",
"classy",
"clean",
"cleaner",
"cleanest",
"cleanly",
"clear",
"clear_cut",
"cleared",
"clearer",
"clever",
"coherent",
"cohesive",
"colorful",
"comely",
"comfortable",
"comforting",
"comfy",
"commendable",
"commodious",
"compact",
"compassionate",
"compatible",
"competitive",
"complementary",
"compliant",
"complimentary",
"comprehensive",
"conciliatory",
"concise",
"confident",
"congenial",
"congratulatory",
"conscientious",
"considerate",
"consistent",
"constructive",
"consummate",
"contrasty",
"convenient",
"convincing",
"cool",
"coolest",
"cooperative",
"correct",
"cost_effective",
"cost_saving",
"courageous",
"courteous",
"courtly",
"cozy",
"creative",
"credible",
"crisp",
"crisper",
"cure_all",
"cushy",
"cute",
"daring",
"darling",
"dashing",
"dauntless",
"dazzled",
"dazzling",
"dead_cheap",
"dead_on",
"decent",
"decisive",
"dedicated",
"defeated",
"deft",
"delectable",
"delicate",
"delicious",
"delighted",
"delightful",
"dependable",
"deserving",
"desirable",
"desirous",
"detachable",
"devout",
"dexterous",
"dextrous",
"dignified",
"diligent",
"diplomatic",
"dirt_cheap",
"distinctive",
"distinguished",
"diversified",
"divine",
"dominated",
"dumbfounded",
"dumbfounding",
"dummy_proof",
"durable",
"dynamic",
"eager",
"earnest",
"eased",
"easier",
"easiest",
"easy",
"easy_to_use",
"easygoing",
"ebullient",
"economical",
"ecstatic",
"educated",
"effective",
"effectual",
"efficacious",
"efficient",
"effortless",
"effusive",
"elated",
"elegant",
"elite",
"eloquent",
"eminent",
"enchanted",
"enchanting",
"encouraging",
"endearing",
"endorsed",
"energetic",
"energy_efficient",
"energy_saving",
"engaging",
"engrossing",
"enhanced",
"enjoyable",
"enough",
"enraptured",
"enterprising",
"entertaining",
"enthralled",
"enthusiastic",
"enticing",
"entranced",
"entrancing",
"enviable",
"envious",
"equitable",
"err_free",
"erudite",
"ethical",
"euphoric",
"evaluative",
"eventful",
"everlasting",
"evocative",
"exalted",
"exalting",
"exceeding",
"excellent",
"exceptional",
"excited",
"exciting",
"exemplary",
"exhilarating",
"expansive",
"exquisite",
"extraordinary",
"exuberant",
"exultant",
"eye_catching",
"fabulous",
"fair",
"faithful",
"famed",
"famous",
"fancier",
"fancy",
"fantastic",
"fascinating",
"fashionable",
"fast",
"fast_growing",
"fast_paced",
"faster",
"fastest",
"fastest_growing",
"faultless",
"favorable",
"favored",
"favorite",
"fearless",
"feasible",
"feature_rich",
"feisty",
"felicitous",
"fertile",
"fervent",
"fervid",
"festive",
"fiery",
"fine",
"fine_looking",
"finer",
"finest",
"firmer",
"first_class",
"first_in_class",
"first_rate",
"flashy",
"flatter",
"flattering",
"flawless",
"flexible",
"flourishing",
"fluent",
"fond",
"foolproof",
"foremost",
"formidable",
"fortuitous",
"fortunate",
"fragrant",
"free",
"freed",
"fresh",
"fresher",
"freshest",
"friendly",
"frugal",
"fruitful",
"fun",
"funny",
"futuristic",
"gainful",
"gallant",
"galore",
"generous",
"genial",
"gentle",
"gentlest",
"genuine",
"gifted",
"glad",
"glamorous",
"gleeful",
"glimmering",
"glistening",
"glorious",
"glowing",
"god_given",
"godlike",
"gold",
"golden",
"good",
"goodly",
"gorgeous",
"graceful",
"gracious",
"grand",
"grateful",
"gratified",
"gratifying",
"great",
"greatest",
"groundbreaking",
"guiltless",
"gutsy",
"halcyon",
"hale",
"hallowed",
"handier",
"hands_down",
"handsome",
"handy",
"happier",
"happy",
"hard_working",
"hardier",
"hardy",
"harmless",
"harmonious",
"healthful",
"healthy",
"heartening",
"heartfelt",
"heartwarming",
"heavenly",
"helpful",
"heroic",
"high_quality",
"high_spirited",
"hilarious",
"holy",
"honest",
"honorable",
"honored",
"hopeful",
"hospitable",
"hot",
"hottest",
"humane",
"humble",
"humorous",
"humourous",
"ideal",
"idolized",
"idyllic",
"illuminating",
"illustrious",
"imaginative",
"immaculate",
"immense",
"impartial",
"impassioned",
"impeccable",
"important",
"impressed",
"impressive",
"improved",
"improving",
"incredible",
"indebted",
"individualized",
"indulgent",
"industrious",
"inestimable",
"inexpensive",
"infallible",
"influential",
"ingenious",
"ingenuous",
"innocuous",
"innovative",
"insightful",
"inspirational",
"inspiring",
"instructive",
"instrumental",
"integral",
"integrated",
"intelligent",
"intelligible",
"interesting",
"intimate",
"intricate",
"intriguing",
"intuitive",
"invaluable",
"inventive",
"invigorating",
"invincible",
"inviolable",
"inviolate",
"invulnerable",
"irreplaceable",
"irreproachable",
"irresistible",
"issue_free",
"jaw_dropping",
"jolly",
"jovial",
"joyful",
"joyous",
"jubilant",
"judicious",
"keen",
"kid_friendly",
"kindly",
"knowledgeable",
"large_capacity",
"laudable",
"lavish",
"law_abiding",
"lawful",
"leading",
"lean",
"legendary",
"light_hearted",
"lighter",
"likable",
"like",
"liked",
"lionhearted",
"lively",
"logical",
"long_lasting",
"lovable",
"loved",
"lovely",
"loving",
"low_cost",
"low_price",
"low_priced",
"low_risk",
"lower_priced",
"loyal",
"lucid",
"luckier",
"luckiest",
"lucky",
"lucrative",
"luminous",
"lush",
"lustrous",
"luxuriant",
"luxurious",
"luxury",
"lyrical",
"magic",
"magical",
"magnanimous",
"magnificent",
"majestic",
"manageable",
"maneuverable",
"marvellous",
"marvelous",
"masterful",
"matchless",
"mature",
"meaningful",
"memorable",
"merciful",
"meritorious",
"merry",
"mesmerized",
"mesmerizing",
"meticulous",
"mighty",
"mind_blowing",
"miraculous",
"modern",
"modest",
"momentous",
"monumental",
"motivated",
"multi_purpose",
"navigable",
"neat",
"neatest",
"nice",
"nicer",
"nicest",
"nifty",
"nimble",
"noble",
"noiseless",
"non_violent",
"noteworthy",
"nourishing",
"observant",
"obtainable",
"optimal",
"optimistic",
"opulent",
"orderly",
"organized",
"outstanding",
"overjoyed",
"pain_free",
"painless",
"palatial",
"pampered",
"panoramic",
"paramount",
"passionate",
"patient",
"patri",
"otic",
"peaceable",
"peaceful",
"peerless",
"peppy",
"perfect",
"permissible",
"personalized",
"phenomenal",
"picturesque",
"playful",
"pleasant",
"pleased",
"pleasing",
"pleasurable",
"plentiful",
"plush",
"poetic",
"poignant",
"poised",
"polished",
"polite",
"popular",
"portable",
"posh",
"positive",
"powerful",
"praiseworthy",
"praising",
"pre_eminent",
"precious",
"precise",
"preeminent",
"preferable",
"premier",
"prestigious",
"pretty",
"priceless",
"principled",
"privileged",
"prize",
"proactive",
"problem_free",
"prodigious",
"productive",
"proficient",
"profound",
"profuse",
"progressive",
"prolific",
"prominent",
"promised",
"promising",
"prompt",
"proper",
"propitious",
"prosperous",
"protective",
"proud",
"proven",
"prudent",
"punctual",
"pure",
"purposeful",
"quaint",
"qualified",
"quicker",
"quiet",
"quieter",
"radiant",
"rapid",
"rapt",
"rapturous",
"rational",
"razor_sharp",
"reachable",
"readable",
"ready",
"realistic",
"realizable",
"reasonable",
"reasoned",
"receptive",
"recommended",
"record_setting",
"redeeming",
"refined",
"reformed",
"refreshed",
"refreshing",
"regal",
"rejoicing",
"relaxed",
"reliable",
"remarkable",
"renewed",
"renowned",
"replaceable",
"reputable",
"resilient",
"resolute",
"resounding",
"resourceful",
"respectable",
"respectful",
"resplendent",
"responsive",
"restful",
"restored",
"retractable",
"reverent",
"revolutionary",
"rewarding",
"rich",
"richer",
"right",
"righteous",
"rightful",
"risk_free",
"robust",
"rock_star",
"romantic",
"roomier",
"roomy",
"rosy",
"safe",
"saintly",
"salutary",
"sane",
"satisfactory",
"satisfied",
"satisfying",
"scenic",
"seamless",
"seasoned",
"secure",
"selective",
"self_determination",
"self_respect",
"self_satisfaction",
"self_sufficiency",
"self_sufficient",
"sensational",
"sensible",
"sensitive",
"serene",
"sexy",
"sharp",
"sharper",
"sharpest",
"shiny",
"significant",
"silent",
"simpler",
"simplest",
"simplified",
"sincere",
"skilled",
"skillful",
"sleek",
"slick",
"smart",
"smarter",
"smartest",
"smiling",
"smitten",
"smooth",
"smoother",
"smoothest",
"snappy",
"snazzy",
"sociable",
"soft",
"softer",
"solicitous",
"solid",
"sophisticated",
"soulful",
"spacious",
"sparkling",
"spectacular",
"speedy",
"spellbinding",
"spellbound",
"spirited",
"spiritual",
"splendid",
"spontaneous",
"sporty",
"spotless",
"sprightly",
"stable",
"stainless",
"state_of_the_art",
"stately",
"statuesque",
"staunch",
"steadfast",
"steadiest",
"steady",
"stellar",
"stimulating",
"stimulative",
"straightforward",
"streamlined",
"striking",
"strong",
"stronger",
"strongest",
"stunned",
"stunning",
"stupendous",
"sturdier",
"sturdy",
"stylish",
"stylized",
"suave",
"sublime",
"subsidized",
"substantive",
"succeeding",
"successful",
"sufficient",
"suitable",
"sumptuous",
"super",
"superb",
"superior",
"supple",
"supported",
"supporting",
"supportive",
"supreme",
"surreal",
"sustainable",
"swank",
"swankier",
"swankiest",
"swanky",
"sweeping",
"sweet",
"sweetheart",
"swift",
"talented",
"tantalizing",
"tempting",
"tenacious",
"tender",
"terrific",
"thankful",
"thinner",
"thoughtful",
"thrifty",
"thrilled",
"thrilling",
"thriving",
"thumb_up",
"thumbs_up",
"tidy",
"time_honored",
"timely",
"titillating",
"tolerable",
"toll_free",
"top",
"top_notch",
"top_quality",
"topnotch",
"tops",
"tough",
"tougher",
"toughest",
"tranquil",
"transparent",
"trendy",
"triumphal",
"triumphant",
"trouble_free",
"trusted",
"trusting",
"trustworthy",
"trusty",
"truthful",
"twinkly",
"ultra_crisp",
"unabashed",
"unaffected",
"unassailable",
"unbeatable",
"unbiased",
"unbound",
"uncomplicated",
"unconditional",
"undamaged",
"undaunted",
"understandable",
"undisputable",
"undisputed",
"unencumbered",
"unequivocal",
"unfettered",
"unforgettable",
"unlimited",
"unmatched",
"unparalleled",
"unquestionable",
"unreal",
"unrestricted",
"unrivaled",
"unselfish",
"unwavering",
"upbeat",
"upscale",
"usable",
"useable",
"useful",
"user_friendly",
"user_replaceable",
"valiant",
"valuable",
"verifiable",
"veritable",
"versatile",
"vibrant",
"victorious",
"viewable",
"vigilant",
"virtuous",
"visionary",
"vivacious",
"vivid",
"warm",
"warmer",
"warmhearted",
"wealthy",
"welcome",
"well",
"well_backlit",
"well_balanced",
"well_behaved",
"well_being",
"well_bred",
"well_connected",
"well_educated",
"well_established",
"well_informed",
"well_intentioned",
"well_known",
"well_made",
"well_managed",
"well_mannered",
"well_positioned",
"well_received",
"well_regarded",
"well_rounded",
"well_run",
"well_wishers",
"wholesome",
"wieldy",
"willing",
"winning",
"wise",
"witty",
"won",
"wonderful",
"wondrous",
"workable",
"world_famous",
"worth",
"worthwhile",
"worthy",
"young",
"youthful",
"zippy"]
export function random_adj() { return adjectives[Math.floor(Math.random() * adjectives.length)] }

View File

@@ -98,7 +98,7 @@ export async function main(
export const MYSQL_INIT_CODE = `import {
mySql,
type Resource
} from "https://deno.land/x/windmill@v${__pkg__.version}/mod.ts";
} from "https://deno.land/x/windmill@v${__pkg__.version}/mysql.ts";
// MySQL parameterized statement. No SQL injection is possible.
export async function main(

View File

@@ -11,8 +11,6 @@
// Default
let schema: Schema = emptySchema()
let nodraft = $page.url.searchParams.get('nodraft')
const templatePath = $page.url.searchParams.get('template')
const hubPath = $page.url.searchParams.get('hub')
@@ -73,4 +71,4 @@
$dirtyStore = true
</script>
<ScriptBuilder {script} />
<ScriptBuilder lockedLanguage={templatePath != null || hubPath != null} {script} />

View File

@@ -4,8 +4,8 @@ verify_ssl = true
name = "pypi"
[packages]
wmill = ">=1.69.0"
wmill_pg = ">=1.69.0"
wmill = ">=1.70.1"
wmill_pg = ">=1.70.1"
sendgrid = "*"
mysql-connector-python = "*"
pymongo = "*"

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.69.0
version: 1.70.1
title: OpenFlow Spec
contact:
name: Ruben Fiszel

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill"
version = "1.69.0"
version = "1.70.1"
description = "A client library for accessing Windmill server wrapping the Windmill client API"
license = "Apache-2.0"
homepage = "https://windmill.dev"
@@ -16,7 +16,7 @@ include = ["wmill/py.typed"]
[tool.poetry.dependencies]
python = "^3.7"
windmill-api = "^1.69.0"
windmill-api = "^1.70.1"
[build-system]
requires = ["poetry>=1.0.2", "poetry-dynamic-versioning"]

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill-pg"
version = "1.69.0"
version = "1.70.1"
description = "An extension client for the wmill client library focused on pg"
license = "Apache-2.0"
homepage = "https://windmill.dev"

View File

@@ -1 +1 @@
1.69.0
1.70.1