Compare commits

..

17 Commits

Author SHA1 Message Date
Ruben Fiszel
4b1bfed090 push 2023-02-24 19:16:11 +01:00
Faton Ramadani
2125d119ff fix(frontend): Fix findGridItem 2023-02-24 19:04:33 +01:00
Faton Ramadani
d3f1ef92ea Merge branch 'rf/flatten' of https://github.com/windmill-labs/windmill into rf/flatten 2023-02-24 19:01:01 +01:00
Faton Ramadani
26296ee05c fix(frontend): Fix findGridItem 2023-02-24 19:00:41 +01:00
Ruben Fiszel
7e4179a741 flatten 2023-02-24 18:52:05 +01:00
Faton Ramadani
52adaa4cb5 fix(frontend): Fix next id 2023-02-24 18:51:50 +01:00
Faton Ramadani
a94f266743 fix(frontend): wip 2023-02-24 18:49:06 +01:00
Faton Ramadani
9d680e6744 Merge branch 'rf/flatten' of https://github.com/windmill-labs/windmill into rf/flatten 2023-02-24 18:44:19 +01:00
Faton Ramadani
5060c37fed fix(frontend): gridtab 2023-02-24 18:44:16 +01:00
Ruben Fiszel
15c2bdcdae pushed 2023-02-24 18:43:44 +01:00
Faton Ramadani
45ce630a75 fix(frontend): duplicate 2023-02-24 18:04:31 +01:00
Faton Ramadani
d50734cbb3 fix(frontend): delete grid item 2023-02-24 17:56:47 +01:00
Ruben Fiszel
b08b559eec script editor panel 2023-02-24 17:53:26 +01:00
Ruben Fiszel
5742bf2235 settings panel 2023-02-24 17:49:16 +01:00
Ruben Fiszel
c56176ec91 Merge branch 'main' into rf/flatten 2023-02-24 17:38:19 +01:00
Faton Ramadani
640242b713 fix(frontend): rewrote utils 2023-02-24 17:17:11 +01:00
Ruben Fiszel
c696f3b6cf flatten 2023-02-24 15:09:38 +01:00
177 changed files with 1461 additions and 5719 deletions

View File

@@ -182,7 +182,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push privately
uses: docker/build-push-action@v4
uses: docker/build-push-action@v3
if: github.event_name != 'pull_request'
with:
context: .
@@ -222,7 +222,7 @@ jobs:
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Build and push privately
uses: docker/build-push-action@v4
uses: docker/build-push-action@v3
if: github.event_name != 'pull_request'
with:
context: .

View File

@@ -65,7 +65,7 @@ jobs:
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Build and push publicly
uses: docker/build-push-action@v4
uses: docker/build-push-action@v3
with:
context: "{{defaultContext}}:lsp"
push: true

View File

@@ -25,12 +25,12 @@ jobs:
run: echo "UUID_TAG_APP=$(uuidgen)" >> $GITHUB_ENV
- name: Docker metadata
id: meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v3
with:
images: registry.uffizzi.com/${{ env.UUID_TAG_APP }}
tags: type=raw,value=60d
- name: Build and Push Image to registry.uffizzi.com ephemeral registry
uses: docker/build-push-action@v4
uses: docker/build-push-action@v2
with:
push: true
context: ./

View File

@@ -1,112 +1,6 @@
# Changelog
## [1.72.0](https://github.com/windmill-labs/windmill/compare/v1.71.0...v1.72.0) (2023-03-02)
### Features
* **backend:** get_result_by_id do a downward pass to find node at any depth ([#1249](https://github.com/windmill-labs/windmill/issues/1249)) ([4c913dc](https://github.com/windmill-labs/windmill/commit/4c913dc4b6be03571a015c97a13829adffb61479))
* **frontend:** Add app map component ([#1251](https://github.com/windmill-labs/windmill/issues/1251)) ([ed25d9f](https://github.com/windmill-labs/windmill/commit/ed25d9f186d9925f75404cb193a025d8a41c4540))
* **frontend:** app splitpanes ([#1248](https://github.com/windmill-labs/windmill/issues/1248)) ([f4d79ee](https://github.com/windmill-labs/windmill/commit/f4d79ee2633e6cdab0fa2410108b31cfa77e10da))
### Bug Fixes
* **backend:** improve result retrieval ([c4463bb](https://github.com/windmill-labs/windmill/commit/c4463bb029907f3c8d77abb194f872aae7876bf6))
* **backend:** incorrect get_result_by_id for list_result job ([2a75cd2](https://github.com/windmill-labs/windmill/commit/2a75cd250ea5e01849fc8bbb69bf44f147d0acb8))
* **cli:** fix workspace option + run script/flow + whoami ([35ea2b2](https://github.com/windmill-labs/windmill/commit/35ea2b27b12159c68c8507ec1f8686028c975387))
* **frontend:** background script not showing inputs ([55eb48c](https://github.com/windmill-labs/windmill/commit/55eb48c55332431304cedbf3bcbbbcff61ec3645))
* **frontend:** fix table bindings ([2679386](https://github.com/windmill-labs/windmill/commit/2679386bf87a56352269911bd89e52df5ee9f314))
* **frontend:** rework app reactivity ([94b20d2](https://github.com/windmill-labs/windmill/commit/94b20d2f5e3b551974c57ea82b6e3dc16e97b9b8))
* **frontend:** rework app reactivity ([1753cb7](https://github.com/windmill-labs/windmill/commit/1753cb7da658f47be974c15da82c71a8e19309a6))
## [1.71.0](https://github.com/windmill-labs/windmill/compare/v1.70.1...v1.71.0) (2023-02-28)
### Features
* **backend:** use counter for sleep/execution/pull durations ([e568690](https://github.com/windmill-labs/windmill/commit/e56869092a03fec4703ddd9ef65c89edb8122962))
* **cli:** add autocompletions ([287b2db](https://github.com/windmill-labs/windmill/commit/287b2db22f7b56e90bcd0c4727c00096695c2e0d))
* **frontend:** App drawer ([#1246](https://github.com/windmill-labs/windmill/issues/1246)) ([8a0d115](https://github.com/windmill-labs/windmill/commit/8a0d1158c4d7e970cb91e1adf4838e5efdbb39ff))
* **frontend:** drawer for editing workspace scripts in flows ([6adc875](https://github.com/windmill-labs/windmill/commit/6adc87561070d8aceaba1838008cd7e6be2e2660))
### Bug Fixes
* **frontend:** Add more app custom css ([#1229](https://github.com/windmill-labs/windmill/issues/1229)) ([a4e4d18](https://github.com/windmill-labs/windmill/commit/a4e4d188ad10443dd0b7f104389594efc768dc59))
* **frontend:** Add more app custom css ([#1247](https://github.com/windmill-labs/windmill/issues/1247)) ([1bb5ed9](https://github.com/windmill-labs/windmill/commit/1bb5ed9ae01fd7998b06833b6222e5dd5d774d35))
* **frontend:** display currently selected filter even if not in list ([42d1cd6](https://github.com/windmill-labs/windmill/commit/42d1cd6456620ba917c560c87d736dc93634adff))
* **frontend:** Fix deeply nested move ([#1245](https://github.com/windmill-labs/windmill/issues/1245)) ([a67f10e](https://github.com/windmill-labs/windmill/commit/a67f10eeb6fdb44bbb3a510badcc5ad0ae187a2b))
* **frontend:** invisible subgrids have h-0 + app policies fix ([2244e83](https://github.com/windmill-labs/windmill/commit/2244e83b9da803a4cf46ab0825d7cb6cb0e24872))
## [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)

View File

@@ -8,9 +8,5 @@ or belonging to one of the below cases:
The files under backend/ are AGPL Licensed.
The files under frontend/ are AGPL Licensed.
The files under python-client/ deno-client/ go-client/ are Apache 2.0 Licensed.
The openapi files, including the OpenFlow spec is Apache 2.0 Licensed.
All third party components incorporated into the Windmill Software are licensed under the
original license provided by the owner of the applicable component.
The files under python-client/ are Apache 2.0 Licensed.
The files under community/ are Apache 2.0 Licensed.

View File

@@ -284,7 +284,6 @@ you to have it being synced automatically everyday.
| ------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| DATABASE_URL | | The Postgres database url. | All |
| DISABLE_NSJAIL | true | Disable Nsjail Sandboxing | Worker |
| SERVER_BIND_ADDR | 0.0.0.0 | IP Address on which to bind listening socket | Server |
| PORT | 8000 | Exposed port | Server | |
| NUM_WORKERS | 3 | The number of worker per Worker instance (set to 1 on Eks to have 1 pod = 1 worker, set to 0 for an API only instance) | Worker |
| DISABLE_SERVER | false | Binary would operate as a worker only instance | Worker |

237
backend/Cargo.lock generated
View File

@@ -129,11 +129,12 @@ dependencies = [
[[package]]
name = "async-lock"
version = "2.7.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7"
checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685"
dependencies = [
"event-listener",
"futures-lite",
]
[[package]]
@@ -254,9 +255,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.6.9"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6137c6234afb339e75e764c866e3594900f0211e1315d33779f269bbe2ec6967"
checksum = "2fb79c228270dcf2426e74864cabc94babb5dbab01a4314e702d2f16540e1591"
dependencies = [
"async-trait",
"axum-core",
@@ -323,9 +324,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
[[package]]
name = "base64ct"
version = "1.6.0"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
[[package]]
name = "better_scoped_tls"
@@ -336,6 +337,15 @@ dependencies = [
"scoped-tls",
]
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bit-set"
version = "0.5.3"
@@ -515,9 +525,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.1.8"
version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [
"bitflags",
"clap_derive",
@@ -530,9 +540,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.1.8"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [
"heck",
"proc-macro-error",
@@ -543,9 +553,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.3.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
dependencies = [
"os_str_bytes",
]
@@ -571,9 +581,9 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.9.2"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
[[package]]
name = "const_format"
@@ -609,7 +619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
dependencies = [
"percent-encoding",
"time 0.3.20",
"time 0.3.19",
"version_check",
]
@@ -694,9 +704,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
]
@@ -956,9 +966,9 @@ checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0"
[[package]]
name = "dyn-clone"
version = "1.0.11"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60"
[[package]]
name = "dyn-iter"
@@ -977,9 +987,9 @@ dependencies = [
[[package]]
name = "ena"
version = "0.14.1"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
@@ -1314,9 +1324,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.3.16"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d"
checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
dependencies = [
"bytes",
"fnv",
@@ -1668,9 +1678,9 @@ checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jobserver"
version = "0.1.26"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [
"libc",
]
@@ -2038,6 +2048,15 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nom8"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
"memchr",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@@ -2084,6 +2103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
dependencies = [
"num-traits",
"serde",
]
[[package]]
@@ -2127,6 +2147,27 @@ dependencies = [
"libc",
]
[[package]]
name = "num_enum"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e0072973714303aa6e3631c7e8e777970cf4bdd25dc4932e41031027b8bcc4e"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0629cbd6b897944899b1f10496d9c4a7ac5878d45fd61bc22e9e79bfbbc29597"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "once_cell"
version = "1.17.1"
@@ -2475,9 +2516,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
dependencies = [
"once_cell",
"toml_edit",
@@ -2525,7 +2566,7 @@ dependencies = [
[[package]]
name = "progenitor"
version = "0.2.1-dev"
source = "git+https://github.com/oxidecomputer/progenitor#cbe875ad1a4c650cf3af595c90df6fd7421b47c2"
source = "git+https://github.com/oxidecomputer/progenitor#82c979df65476fe4dfc2590970ccdf64113e9e0c"
dependencies = [
"anyhow",
"built",
@@ -2543,7 +2584,7 @@ dependencies = [
[[package]]
name = "progenitor-client"
version = "0.2.1-dev"
source = "git+https://github.com/oxidecomputer/progenitor#cbe875ad1a4c650cf3af595c90df6fd7421b47c2"
source = "git+https://github.com/oxidecomputer/progenitor#82c979df65476fe4dfc2590970ccdf64113e9e0c"
dependencies = [
"bytes",
"futures-core",
@@ -2557,7 +2598,7 @@ dependencies = [
[[package]]
name = "progenitor-impl"
version = "0.2.1-dev"
source = "git+https://github.com/oxidecomputer/progenitor#cbe875ad1a4c650cf3af595c90df6fd7421b47c2"
source = "git+https://github.com/oxidecomputer/progenitor#82c979df65476fe4dfc2590970ccdf64113e9e0c"
dependencies = [
"getopts",
"heck",
@@ -2579,7 +2620,7 @@ dependencies = [
[[package]]
name = "progenitor-macro"
version = "0.2.1-dev"
source = "git+https://github.com/oxidecomputer/progenitor#cbe875ad1a4c650cf3af595c90df6fd7421b47c2"
source = "git+https://github.com/oxidecomputer/progenitor#82c979df65476fe4dfc2590970ccdf64113e9e0c"
dependencies = [
"openapiv3",
"proc-macro2",
@@ -2757,6 +2798,15 @@ 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"
@@ -2953,7 +3003,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython#6e4c2fe7866f705bb427200a36d6c9fb46508de3"
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
dependencies = [
"num-bigint",
"rustpython-compiler-core",
@@ -2962,20 +3012,24 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython#6e4c2fe7866f705bb427200a36d6c9fb46508de3"
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
dependencies = [
"bincode",
"bitflags",
"bstr",
"itertools",
"lz4_flex",
"num-bigint",
"num-complex",
"num_enum",
"serde",
"thiserror",
]
[[package]]
name = "rustpython-parser"
version = "0.2.0"
source = "git+https://github.com/RustPython/RustPython#6e4c2fe7866f705bb427200a36d6c9fb46508de3"
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
dependencies = [
"ahash",
"anyhow",
@@ -2990,6 +3044,7 @@ dependencies = [
"rustc-hash",
"rustpython-ast",
"rustpython-compiler-core",
"thiserror",
"tiny-keccak",
"unic-emoji-char",
"unic-ucd-ident",
@@ -3028,9 +3083,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.12"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
dependencies = [
"chrono",
"dyn-clone",
@@ -3042,9 +3097,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.12"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
dependencies = [
"proc-macro2",
"quote",
@@ -3642,9 +3697,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "swc_atoms"
version = "0.4.38"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a172f2e444ae1378286cd27ff2a5cb26eadfd7a77c98ccb0edde8992857be1e"
checksum = "f88175a66f5a7c189e752bda520e148317776ecb22c75adc2c2f24c490834bd0"
dependencies = [
"once_cell",
"rustc-hash",
@@ -3656,9 +3711,9 @@ dependencies = [
[[package]]
name = "swc_common"
version = "0.29.33"
version = "0.29.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a75c46065858a37cdda2c1c6fd056986e3b7752d5ec332e91ce312c6a22749"
checksum = "1fc8e0e8109b26be70c82d9709562fc88cbcc09e03c2458221cf216c0088dea2"
dependencies = [
"ahash",
"ast_node",
@@ -3683,9 +3738,9 @@ dependencies = [
[[package]]
name = "swc_ecma_ast"
version = "0.98.0"
version = "0.96.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1f6bc913d0f1daf0fa713a64660aed27848e0047ee671ab2206ad602730d1f"
checksum = "621c66e27fbb6cbb6434a4e2b25e439e9a2583cc3419a4a83eba51d16ac0cd7b"
dependencies = [
"bitflags",
"is-macro",
@@ -3700,9 +3755,9 @@ dependencies = [
[[package]]
name = "swc_ecma_parser"
version = "0.127.0"
version = "0.124.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3875db58a1515382c670679062133294e5ec88aff08776f5fb6e4f3c09c0f5f9"
checksum = "89b3f472b3dfbfd279de364d2b014459a281824b938e243a8739037c445d6b6c"
dependencies = [
"either",
"enum_kind",
@@ -3768,9 +3823,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.109"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
dependencies = [
"proc-macro2",
"quote",
@@ -3785,15 +3840,16 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "tempfile"
version = "3.4.0"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"rustix",
"windows-sys 0.42.0",
"remove_dir_all",
"winapi",
]
[[package]]
@@ -3870,9 +3926,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.20"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2"
dependencies = [
"itoa",
"serde",
@@ -3888,9 +3944,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
[[package]]
name = "time-macros"
version = "0.2.8"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c"
dependencies = [
"time-core",
]
@@ -3921,9 +3977,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.26.0"
version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
dependencies = [
"autocfg",
"bytes",
@@ -3937,7 +3993,7 @@ dependencies = [
"socket2",
"tokio-macros",
"tracing",
"windows-sys 0.45.0",
"windows-sys 0.42.0",
]
[[package]]
@@ -4034,19 +4090,19 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.1"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
[[package]]
name = "toml_edit"
version = "0.19.4"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825"
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
dependencies = [
"indexmap",
"nom8",
"toml_datetime",
"winnow",
]
[[package]]
@@ -4097,9 +4153,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.4.0"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658"
checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858"
dependencies = [
"bitflags",
"bytes",
@@ -4244,7 +4300,7 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "typify"
version = "0.0.11-dev"
source = "git+https://github.com/oxidecomputer/typify#05d65ea62be9061c1abd0c31d955d0248120d301"
source = "git+https://github.com/oxidecomputer/typify#d579a526b3cc2e0c36d17fae8df549a03187f177"
dependencies = [
"typify-impl",
"typify-macro",
@@ -4253,7 +4309,7 @@ dependencies = [
[[package]]
name = "typify-impl"
version = "0.0.11-dev"
source = "git+https://github.com/oxidecomputer/typify#05d65ea62be9061c1abd0c31d955d0248120d301"
source = "git+https://github.com/oxidecomputer/typify#d579a526b3cc2e0c36d17fae8df549a03187f177"
dependencies = [
"heck",
"log",
@@ -4271,7 +4327,7 @@ dependencies = [
[[package]]
name = "typify-macro"
version = "0.0.11-dev"
source = "git+https://github.com/oxidecomputer/typify#05d65ea62be9061c1abd0c31d955d0248120d301"
source = "git+https://github.com/oxidecomputer/typify#d579a526b3cc2e0c36d17fae8df549a03187f177"
dependencies = [
"proc-macro2",
"quote",
@@ -4419,11 +4475,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "unicode_names2"
version = "0.6.0"
source = "git+https://github.com/youknowone/unicode_names2.git?tag=v0.6.0+character-alias#4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde"
dependencies = [
"phf",
]
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029df4cc8238cefc911704ff8fa210853a0f3bce2694d8f51181dd41ee0f3301"
[[package]]
name = "unsafe-libyaml"
@@ -4712,7 +4766,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"axum",
@@ -4739,7 +4793,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"argon2",
@@ -4772,7 +4826,7 @@ dependencies = [
"sql-builder",
"sqlx",
"tempfile",
"time 0.3.20",
"time 0.3.19",
"tokio",
"tokio-tar",
"tokio-util",
@@ -4794,7 +4848,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"base64 0.21.0",
"chrono",
@@ -4809,7 +4863,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"chrono",
"serde",
@@ -4822,7 +4876,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"axum",
@@ -4847,7 +4901,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"serde",
"serde_json",
@@ -4855,7 +4909,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"itertools",
@@ -4869,7 +4923,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"itertools",
@@ -4881,7 +4935,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"itertools",
@@ -4896,7 +4950,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"deno_core",
@@ -4910,7 +4964,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"chrono",
@@ -4933,7 +4987,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.72.0"
version = "1.69.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -5047,15 +5101,6 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "winnow"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.10.1"

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,16 +0,0 @@
-- Add up migration script here
UPDATE script SET content = 'import wmill from "https://deno.land/x/wmill@v1.70.1/main.ts";
export async function main() {
await run(
"workspace", "add", "__automation", "admins", Deno.env.get("BASE_INTERNAL_URL") + "/", "--token", Deno.env.get("WM_TOKEN"));
await run("hub", "pull");
}
async function run(...cmd: string[]) {
console.log("Running \"" + cmd.join('' '') + "\"");
await wmill.parse(cmd);
}', summary = 'Synchronize Hub Resource types with admins workspace',
description = 'Basic administrative script to sync latest resource types from hub to share to every workspace. Recommended to run at least once. On a schedule by default.'
WHERE hash = -28028598712388162 AND workspace_id = 'admins';

View File

@@ -550,6 +550,21 @@
},
"query": "SELECT * FROM workspace LIMIT $1 OFFSET $2"
},
"15de975d9be141c9ed9647935a508492aabbbddbf986d5c5c0f0c415293c432d": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Varchar",
"Varchar"
]
}
},
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description)\n VALUES ($1, 'g/all/pretty_secret', $2, true, 'This item is secret'), \n ($3, 'g/all/not_secret', $4, false, 'This item is not secret')"
},
"163f00eb8b1a489d5f382cdba22a5744e88a8e6f1532d7cb02af560f5f5d49f7": {
"describe": {
"columns": [
@@ -645,27 +660,6 @@
},
"query": "SELECT * FROM workspace_settings WHERE workspace_id = $1"
},
"176afff6dfceac701d499663f15fb7f569fd9d449406df4c5ecc811414429d42": {
"describe": {
"columns": [
{
"name": "flow_status",
"ordinal": 0,
"type_info": "Jsonb"
}
],
"nullable": [
null
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
}
},
"query": "SELECT flow_status FROM completed_job WHERE id = $1 AND workspace_id = $2 \n UNION ALL SELECT flow_status FROM queue WHERE id = $1 AND workspace_id = $2 "
},
"187a27d18f78f068319a0ec684f71a76c49dd09c5c74c2c777e35233c4f5a281": {
"describe": {
"columns": [
@@ -1189,6 +1183,33 @@
},
"query": "UPDATE script SET archived = true WHERE hash = $1 AND workspace_id = $2"
},
"2be0cfd075df9624ccbcbe5fd645e0a5c25460c2d01493f86dcdd9b2b71f6181": {
"describe": {
"columns": [
{
"name": "flow_status",
"ordinal": 0,
"type_info": "Jsonb"
},
{
"name": "parent_job",
"ordinal": 1,
"type_info": "Uuid"
}
],
"nullable": [
null,
null
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
}
},
"query": "SELECT flow_status, parent_job FROM completed_job WHERE id = $1 AND workspace_id = $2 UNION ALL SELECT flow_status, parent_job FROM queue WHERE id = $1 AND workspace_id = $2 "
},
"2e4115bb2e6c8c85ad1492ad135d6b0454b342126cb5fa17e58caf71b32ee755": {
"describe": {
"columns": [],
@@ -3657,33 +3678,6 @@
},
"query": "SELECT is_admin FROM usr where username = $1 AND workspace_id = $2 AND disabled = false"
},
"92ce38eaaef9e793a49788bf3b7fc88340e83da57b785364a477f08c776f66f3": {
"describe": {
"columns": [
{
"name": "flow_status",
"ordinal": 0,
"type_info": "Jsonb"
},
{
"name": "parent_job",
"ordinal": 1,
"type_info": "Uuid"
}
],
"nullable": [
null,
null
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
}
},
"query": "SELECT flow_status, parent_job FROM completed_job WHERE id = $1 AND workspace_id = $2 \n UNION ALL SELECT flow_status, parent_job FROM queue WHERE id = $1 AND workspace_id = $2 "
},
"930ad84a4db26fa6d2c8447d447099e944a0ea7b1266b4d02cee620fe3d761a5": {
"describe": {
"columns": [],

View File

@@ -6,7 +6,7 @@
* LICENSE-AGPL for a copy of the license.
*/
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::SocketAddr;
use git_version::git_version;
use sqlx::{Pool, Postgres};
@@ -15,7 +15,6 @@ use windmill_common::utils::rd_string;
const GIT_VERSION: &str = git_version!(args = ["--tag", "--always"], fallback = "unknown-version");
const DEFAULT_NUM_WORKERS: usize = 3;
const DEFAULT_PORT: u16 = 8000;
const DEFAULT_SERVER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
mod ee;
@@ -40,11 +39,6 @@ async fn main() -> anyhow::Result<()> {
.transpose()?
.flatten();
let server_bind_address: IpAddr = std::env::var("SERVER_BIND_ADDR")
.ok()
.and_then(|x| x.parse().ok() )
.unwrap_or(IpAddr::from(DEFAULT_SERVER_BIND_ADDR));
let port: u16 = std::env::var("PORT")
.ok()
.and_then(|x| x.parse::<u16>().ok())
@@ -66,63 +60,8 @@ async fn main() -> anyhow::Result<()> {
let (tx, rx) = tokio::sync::broadcast::channel::<()>(3);
let shutdown_signal = windmill_common::shutdown_signal(tx);
#[cfg(feature = "enterprise")]
tracing::info!(
"
##############################
Windmill Enterprise Edition {GIT_VERSION}
##############################"
);
#[cfg(not(feature = "enterprise"))]
tracing::info!(
"
##############################
Windmill Community Edition {GIT_VERSION}
##############################"
);
display_config(vec![
"DISABLE_NSJAIL",
"DISABLE_SERVER",
"NUM_WORKERS",
"METRICS_ADDR",
"JSON_FMT",
"BASE_URL",
"BASE_INTERNAL_URL",
"TIMEOUT",
"SLEEP_QUEUE",
"MAX_LOG_SIZE",
"SERVER_BIND_ADDR",
"PORT",
"KEEP_JOB_DIR",
"S3_CACHE_BUCKET",
"TAR_CACHE_RATE",
"COOKIE_DOMAIN",
"PYTHON_PATH",
"DENO_PATH",
"GO_PATH",
"PIP_INDEX_URL",
"PIP_EXTRA_INDEX_URL",
"PIP_TRUSTED_HOST",
"PATH",
"HOME",
"DATABASE_CONNECTIONS",
"TIMEOUT_WAIT_RESULT",
"QUEUE_LIMIT_WAIT_RESULT",
"DENO_AUTH_TOKENS",
"DENO_FLAGS",
"PIP_LOCAL_DEPENDENCIES",
"ADDITIONAL_PYTHON_PATHS",
"INCLUDE_HEADERS",
"WHITELIST_WORKSPACES",
"BLACKLIST_WORKSPACES",
"NEW_USER_WEBHOOK",
"CLOUD_HOSTED",
]);
if server_mode || num_workers > 0 {
let addr = SocketAddr::from((server_bind_address, port));
let addr = SocketAddr::from(([0, 0, 0, 0], port));
let server_f = async {
if server_mode {
@@ -133,6 +72,60 @@ Windmill Community Edition {GIT_VERSION}
let workers_f = async {
if num_workers > 0 {
#[cfg(feature = "enterprise")]
tracing::info!(
"
##############################
Windmill Enterprise Edition {GIT_VERSION}
##############################"
);
#[cfg(not(feature = "enterprise"))]
tracing::info!(
"
##############################
Windmill Community Edition {GIT_VERSION}
##############################"
);
display_config(vec![
"DISABLE_NSJAIL",
"DISABLE_SERVER",
"NUM_WORKERS",
"METRICS_ADDR",
"JSON_FMT",
"BASE_URL",
"BASE_INTERNAL_URL",
"TIMEOUT",
"SLEEP_QUEUE",
"MAX_LOG_SIZE",
"PORT",
"KEEP_JOB_DIR",
"S3_CACHE_BUCKET",
"TAR_CACHE_RATE",
"COOKIE_DOMAIN",
"PYTHON_PATH",
"DENO_PATH",
"GO_PATH",
"PIP_INDEX_URL",
"PIP_EXTRA_INDEX_URL",
"PIP_TRUSTED_HOST",
"PATH",
"HOME",
"DATABASE_CONNECTIONS",
"TIMEOUT_WAIT_RESULT",
"QUEUE_LIMIT_WAIT_RESULT",
"DENO_AUTH_TOKENS",
"DENO_FLAGS",
"PIP_LOCAL_DEPENDENCIES",
"ADDITIONAL_PYTHON_PATHS",
"INCLUDE_HEADERS",
"WHITELIST_WORKSPACES",
"BLACKLIST_WORKSPACES",
"NEW_USER_WEBHOOK",
"CLOUD_HOSTED",
]);
run_workers(
db.clone(),
rx.resubscribe(),

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.72.0
version: 1.69.0
title: Windmill API
contact:
@@ -3337,22 +3337,6 @@ paths:
schema:
$ref: "#/components/schemas/CompletedJob"
/w/{workspace}/jobs/completed/get_result/{id}:
get:
summary: get completed job result
operationId: getCompletedJobResult
tags:
- job
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/JobId"
responses:
"200":
description: result
content:
application/json:
schema: {}
/w/{workspace}/jobs/completed/delete/{id}:
post:
summary: delete completed job (erase content but keep run id)

View File

@@ -7,12 +7,11 @@
*/
use axum::{
extract::{Extension, Path, Query},
extract::{Extension, Path},
routing::{get, post, put},
Json, Router,
};
use hyper::{HeaderMap, StatusCode};
use serde::Deserialize;
use hyper::StatusCode;
use windmill_common::{
error::{JsonResult, Result},
utils::{not_found_if_none, StripPath},
@@ -20,7 +19,6 @@ use windmill_common::{
use crate::{
db::{UserDB, DB},
jobs::add_include_headers,
users::Authed,
};
@@ -85,21 +83,13 @@ pub async fn new_payload(
Ok(StatusCode::CREATED)
}
#[derive(Deserialize, Clone)]
pub struct IncludeHeaderQuery {
include_header: Option<String>,
}
pub async fn update_payload(
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
Query(run_query): Query<IncludeHeaderQuery>,
headers: HeaderMap,
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
Json(payload): Json<serde_json::Value>,
) -> Result<StatusCode> {
let mut tx = db.begin().await?;
let args = add_include_headers(&run_query.include_header, headers, args.unwrap_or_default());
sqlx::query!(
"
UPDATE capture
@@ -109,7 +99,7 @@ pub async fn update_payload(
",
&w_id,
&path.to_path(),
serde_json::json!(args),
&payload,
)
.execute(&mut tx)
.await?;

View File

@@ -295,38 +295,28 @@ impl RunJobQuery {
fn add_include_headers(
&self,
headers: HeaderMap,
args: serde_json::Map<String, serde_json::Value>,
mut args: serde_json::Map<String, serde_json::Value>,
) -> serde_json::Map<String, serde_json::Value> {
return add_include_headers(&self.include_header, headers, args);
let whitelist = self
.include_header
.as_ref()
.map(|s| s.split(",").map(|s| s.to_string()).collect::<Vec<_>>())
.unwrap_or_default();
whitelist
.iter()
.chain(INCLUDE_HEADERS.iter())
.for_each(|h| {
if let Some(v) = headers.get(h) {
args.insert(
h.to_string().to_lowercase().replace('-', "_"),
serde_json::Value::String(v.to_str().unwrap().to_string()),
);
}
});
args
}
}
pub fn add_include_headers(
include_header: &Option<String>,
headers: HeaderMap,
mut args: serde_json::Map<String, serde_json::Value>,
) -> serde_json::Map<String, serde_json::Value> {
if include_header.is_none() {
return args;
}
let whitelist = include_header
.as_ref()
.map(|s| s.split(",").map(|s| s.to_string()).collect::<Vec<_>>())
.unwrap_or_default();
whitelist
.iter()
.chain(INCLUDE_HEADERS.iter())
.for_each(|h| {
if let Some(v) = headers.get(h) {
args.insert(
h.to_string().to_lowercase().replace('-', "_"),
serde_json::Value::String(v.to_str().unwrap().to_string()),
);
}
});
args
}
#[derive(Deserialize)]
pub struct ListQueueQuery {
pub script_path_start: Option<String>,
@@ -1785,7 +1775,6 @@ async fn get_completed_job(
.fetch_optional(&db)
.await?;
tracing::info!("job_o: {:?}", job_o);
let job = not_found_if_none(job_o, "Completed Job", id.to_string())?;
Ok(Json(job))
}

View File

@@ -1311,9 +1311,7 @@ async fn create_user(
if let Some(new_user_webhook) = NEW_USER_WEBHOOK.clone() {
let _ = HTTP_CLIENT
.post(&new_user_webhook)
.json(
&serde_json::json!({"email" : &nu.email, "name": &nu.name, "event": "global_add"}),
)
.json(&serde_json::json!({"email" : &nu.email, "name": &nu.name, "event": "new_user"}))
.send()
.await
.map_err(|e| tracing::error!("Error sending new user webhook: {}", e.to_string()));

View File

@@ -6,10 +6,10 @@
* LICENSE-AGPL for a copy of the license.
*/
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
use std::str::FromStr;
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
use crate::BASE_URL;
use crate::{
apps::AppWithLastVersion,
@@ -20,7 +20,7 @@ use crate::{
utils::require_super_admin,
HTTP_CLIENT,
};
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
use axum::response::Redirect;
use axum::{
body::StreamBody,
@@ -30,7 +30,7 @@ use axum::{
routing::{delete, get, post},
Json, Router,
};
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
use stripe::CustomerId;
use windmill_audit::{audit_log, ActionKind};
use windmill_common::{
@@ -63,13 +63,12 @@ pub fn workspaced_service() -> Router {
.route("/tarball", get(tarball_workspace))
.route("/premium_info", get(premium_info));
#[cfg(feature = "enterprise")]
tracing::info!("stripe enabled");
#[cfg(feature = "enterprise")]
let router = router
.route("/checkout", get(stripe_checkout))
.route("/billing_portal", get(stripe_portal));
#[cfg(enterprise)]
let router = {
router
.route("/checkout", get(stripe_checkout))
.route("/billing_portal", get(stripe_portal));
};
router
}
@@ -231,13 +230,13 @@ async fn premium_info(
Ok(Json(row))
}
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
#[derive(Deserialize)]
struct PlanQuery {
plan: String,
}
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
async fn stripe_checkout(
authed: Authed,
Path(w_id): Path<String>,
@@ -303,7 +302,7 @@ async fn stripe_checkout(
}
}
#[cfg(feature = "enterprise")]
#[cfg(enterprise)]
async fn stripe_portal(
authed: Authed,
Path(w_id): Path<String>,
@@ -965,7 +964,7 @@ async fn invite_user(
if let Some(new_user_webhook) = NEW_USER_WEBHOOK.clone() {
let _ = &HTTP_CLIENT
.post(&new_user_webhook)
.json(&serde_json::json!({"email" : &nu.email, "event": "workspace_invite"}))
.json(&serde_json::json!({"email" : &nu.email, "event": "new_invite"}))
.send()
.await
.map_err(|e| tracing::error!("Error sending new user webhook: {}", e.to_string()));
@@ -1002,15 +1001,6 @@ async fn add_user(
tx.commit().await?;
if let Some(new_user_webhook) = NEW_USER_WEBHOOK.clone() {
let _ = HTTP_CLIENT
.post(&new_user_webhook)
.json(&serde_json::json!({"email" : &nu.email, "event": "workspace_add"}))
.send()
.await
.map_err(|e| tracing::error!("Error sending new user webhook: {}", e.to_string()));
}
Ok((
StatusCode::CREATED,
format!("user with email {} added", nu.email),

View File

@@ -6,10 +6,7 @@
* LICENSE-AGPL for a copy of the license.
*/
use std::{
collections::{HashMap, VecDeque},
str::FromStr,
};
use std::{collections::HashMap, str::FromStr};
use anyhow::Context;
use reqwest::Client;
@@ -20,7 +17,7 @@ use ulid::Ulid;
use uuid::Uuid;
use windmill_audit::{audit_log, ActionKind};
use windmill_common::{
error::{self, to_anyhow, Error},
error::{self, Error},
flow_status::{FlowStatus, JobResult, MAX_RETRY_ATTEMPTS, MAX_RETRY_INTERVAL},
flows::{FlowModule, FlowModuleValue, FlowValue},
scripts::{get_full_hub_script_by_path, HubScript, ScriptHash, ScriptLang},
@@ -153,41 +150,6 @@ pub async fn pull(
Ok(job)
}
pub async fn find_recursively_downward(
db: &Pool<Postgres>,
w_id: &str,
flow_id: Uuid,
node_id: &str,
) -> windmill_common::error::Result<Option<JobResult>> {
let mut bfs_stack = VecDeque::new();
bfs_stack.push_back(flow_id);
while bfs_stack.len() > 0 {
let parent_id = bfs_stack.pop_front().unwrap();
let job = sqlx::query_scalar!(
"SELECT flow_status FROM completed_job WHERE id = $1 AND workspace_id = $2
UNION ALL SELECT flow_status FROM queue WHERE id = $1 AND workspace_id = $2 ",
parent_id,
w_id
)
.fetch_optional(db)
.await?
.flatten();
if let Some(r) = job {
let status = serde_json::from_value::<FlowStatus>(r).map_err(to_anyhow)?;
for m in status.modules.iter() {
let id = m.id();
if id == node_id {
return Ok(m.job_result());
}
if let Some(job_id) = m.job() {
bfs_stack.push_back(job_id);
}
}
}
}
Ok(None)
}
pub async fn get_result_by_id(
db: Pool<Postgres>,
mut skip_direct: bool,
@@ -197,12 +159,10 @@ pub async fn get_result_by_id(
) -> error::Result<serde_json::Value> {
let mut result_id: Option<JobResult> = None;
let mut parent_id = Uuid::from_str(&flow_id).ok();
let mut lparent_id = parent_id.clone();
while result_id.is_none() && parent_id.is_some() {
if !skip_direct {
let r = sqlx::query!(
"SELECT flow_status, parent_job FROM completed_job WHERE id = $1 AND workspace_id = $2
UNION ALL SELECT flow_status, parent_job FROM queue WHERE id = $1 AND workspace_id = $2 ",
"SELECT flow_status, parent_job FROM completed_job WHERE id = $1 AND workspace_id = $2 UNION ALL SELECT flow_status, parent_job FROM queue WHERE id = $1 AND workspace_id = $2 ",
parent_id.unwrap(),
w_id,
)
@@ -214,7 +174,6 @@ pub async fn get_result_by_id(
.as_ref()
.ok_or_else(|| Error::InternalErr(format!("requiring a flow status value")))?
.to_owned();
lparent_id = parent_id;
parent_id = r.parent_job;
let status_o = serde_json::from_value::<FlowStatus>(value).ok();
result_id = status_o.and_then(|status| {
@@ -236,17 +195,10 @@ pub async fn get_result_by_id(
.fetch_optional(&db)
.await?
.flatten();
lparent_id = parent_id;
parent_id = q_parent;
skip_direct = false
}
}
// we could not find the node going upward from the flow by looking at all the jobs (in progress or completed)
// we now look downward from the flow root to the all the children completed job for a job that might hide itself
// in a deep non-direct parent job such as in nested branches
if result_id.is_none() && lparent_id.is_some() {
result_id = find_recursively_downward(&db, &w_id, lparent_id.unwrap(), &node_id).await?;
}
let result_id = windmill_common::utils::not_found_if_none(
result_id,
"Flow result by id",
@@ -399,10 +351,7 @@ pub async fn push<'c>(
.unwrap_or(false);
if !is_super_admin {
if usage > MAX_FREE_EXECS
&& !matches!(job_payload, JobPayload::Dependencies { .. })
&& !matches!(job_payload, JobPayload::FlowDependencies { .. })
{
if usage > MAX_FREE_EXECS {
return Err(error::Error::BadRequest(format!(
"User {email} has exceeded the free usage limit of {MAX_FREE_EXECS} that applies outside of premium workspaces."
)));
@@ -517,10 +466,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

@@ -145,7 +145,7 @@ fn add_closing_bracket(s: &str) -> String {
s
}
const SPLIT_PAT: &str = ";";
const SPLIT_PAT: &str = ";\n";
async fn eval(
context: &mut JsRuntime,
expr: &str,
@@ -154,21 +154,14 @@ async fn eval(
by_id: Option<IdContext>,
base_internal_url: &str,
) -> anyhow::Result<serde_json::Value> {
let exprs = expr
.trim()
.split(SPLIT_PAT)
.map(|x| x.trim())
.filter(|x| !x.is_empty())
.collect::<Vec<&str>>();
let expr = if exprs.is_empty() {
"return undefined;".to_string()
} else {
format!(
"{};\n return {};",
exprs.iter().take(exprs.len() - 1).join(";\n"),
exprs.last().unwrap()
)
};
let expr = expr.trim();
let expr = format!(
"{}\nreturn {};",
expr.split(SPLIT_PAT)
.take(expr.split(SPLIT_PAT).count() - 1)
.join("\n"),
expr.split(SPLIT_PAT).last().unwrap_or_else(|| "")
);
let (api_code, by_id_code) = if let Some(EvalCreds { workspace, token }) = creds {
let by_id_code = if let Some(by_id) = by_id {
format!(
@@ -205,12 +198,12 @@ const results = new Proxy({{}}, {{
.into_iter()
.map(|(k, v)| {
let v_str = match v {
JobResult::SingleJob(x) => format!("\"{x}\""),
JobResult::SingleJob(x) => x.to_string(),
JobResult::ListJob(x) => {
format!("[{}]", x.iter().map(|x| format!("\"{x}\"")).join(","))
format!("[{}]", x.iter().map(|x| x.to_string()).join(","))
}
};
format!("\"{k}\": {v_str}")
format!("\"{k}\": \"{v_str}\"")
})
.join(","),
by_id.previous_id,
@@ -299,8 +292,9 @@ async fn op_get_result(args: Vec<String>) -> Result<serde_json::Value, anyhow::E
let base_url = &args[3];
let client = windmill_api_client::create_client(base_url, token.clone());
let result = client
.get_completed_job_result(workspace, &id.parse()?)
.get_completed_job(workspace, &id.parse()?)
.await?
.result
.clone();
Ok(serde_json::json!(result))
}

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 seconds since the worker has started"
"Total number of milliseconds since the worker has started"
);
static ref TIMEOUT: u16 = std::env::var("TIMEOUT")
@@ -445,11 +445,15 @@ pub async fn run_worker(
insert_initial_ping(worker_instance, &worker_name, ip, db).await;
let uptime_metric = prometheus::register_counter!(WORKER_UPTIME_OPTS
let uptime_metric = prometheus::register_int_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(
@@ -461,14 +465,6 @@ 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",
@@ -476,15 +472,6 @@ 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_sleep_duration_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",
@@ -492,13 +479,6 @@ 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_duration_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),
@@ -546,12 +526,11 @@ pub async fn run_worker(
worker_busy.set(0);
uptime_metric.inc_by(
(((Instant::now() - start_time).as_millis() as f64)/1000.0 - uptime_metric.get())
((Instant::now() - start_time).as_millis() - uptime_metric.get() as u128)
.try_into()
.unwrap(),
);
let do_break = async {
if last_ping.elapsed().as_secs() > NUM_SECS_ENV_CHECK {
sqlx::query!(
@@ -595,8 +574,7 @@ 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)) } => {
let duration_pull_s = timer.stop_and_record();
worker_pull_duration_counter.inc_by(duration_pull_s);
drop(timer);
(false, job)
},
}
@@ -702,8 +680,6 @@ 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;
@@ -713,9 +689,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

@@ -23,7 +23,7 @@ async function tryResolveWorkspace(
{ isError: false; value: Workspace } | { isError: true; error: string }
> {
const cache = (opts as any).__secret_workspace;
if (cache) return { isError: false, value: cache };
if (cache) return cache;
if (opts.workspace) {
const e = await getWorkspaceByName(opts.workspace);
@@ -53,6 +53,7 @@ export async function resolveWorkspace(
): Promise<Workspace> {
const res = await tryResolveWorkspace(opts);
if (res.isError) {
console.log(res.error);
return Deno.exit(-1);
} else {
return res.value;
@@ -61,8 +62,8 @@ export async function resolveWorkspace(
export async function requireLogin(opts: GlobalOptions): Promise<GlobalUserInfo> {
const workspace = await resolveWorkspace(opts);
let token = await tryGetLoginInfo(opts);
let token = await tryGetLoginInfo(opts);
if (!token) {
token = workspace.token;
}
@@ -79,9 +80,9 @@ export async function requireLogin(opts: GlobalOptions): Promise<GlobalUserInfo>
if (!newToken) {
throw new Error("Could not reauth");
}
removeWorkspace(workspace.name, false, opts);
removeWorkspace(workspace.name);
workspace.token = newToken;
addWorkspace(workspace, opts);
addWorkspace(workspace);
setClient(
token,

View File

@@ -1,6 +1,6 @@
// windmill
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";
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";
// cliffy
export { Command } from "https://deno.land/x/cliffy@v0.25.7/command/command.ts";
@@ -14,7 +14,7 @@ export {
DenoLandProvider,
UpgradeCommand,
} from "https://deno.land/x/cliffy@v0.25.7/command/upgrade/mod.ts";
export { CompletionsCommand } from "https://deno.land/x/cliffy@v0.25.7/command/completions/mod.ts";
// std
export * as path from "https://deno.land/std@0.176.0/path/mod.ts";
export { ensureDir } from "https://deno.land/std@0.176.0/fs/ensure_dir.ts";

View File

@@ -192,7 +192,7 @@ async function list(opts: GlobalOptions & { showArchived?: boolean }) {
}
async function run(
opts: GlobalOptions & {
data?: string;
input: string[];
silent: boolean;
},
path: string,
@@ -200,8 +200,7 @@ async function run(
const workspace = await resolveWorkspace(opts);
await requireLogin(opts);
const input = opts.data ? await resolve(opts.data) : {};
const input = await resolve(opts.input);
const id = await JobService.runFlowByPath({
workspace: workspace.workspaceId,
@@ -237,7 +236,6 @@ async function run(
if (!opts.silent) {
console.log(colors.green.underline.bold("Flow ran to completion"));
console.log()
}
const jobInfo = await JobService.getCompletedJob({
workspace: workspace.workspaceId,
@@ -259,8 +257,8 @@ const command = new Command()
.command("run", "run a flow by path.")
.arguments("<path:string>")
.option(
"-d --data <data:string>",
"Inputs specified as a JSON string or a file using @<filename> or stdin using @-.",
"-i --input [inputs...:string]",
"Inputs specified as JSON objects or simply as <name>=<value>. Supports file inputs using @<filename> and stdin using @- these also need to be formatted as JSON. Later inputs override earlier ones.",
)
.option(
"-s --silent",

View File

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

View File

@@ -1,4 +1,4 @@
import { Command, CompletionsCommand, DenoLandProvider, UpgradeCommand } from "./deps.ts";
import { Command, DenoLandProvider, UpgradeCommand } from "./deps.ts";
import flow from "./flow.ts";
import script from "./script.ts";
import workspace from "./workspace.ts";
@@ -13,7 +13,7 @@ import sync from "./sync.ts";
import { tryResolveVersion } from "./context.ts";
import { GlobalOptions } from "./types.ts";
const VERSION = "v1.72.0";
const VERSION = "v1.69.0";
let command: any = new Command()
.name("wmill")
@@ -60,8 +60,7 @@ let command: any = new Command()
],
provider: new DenoLandProvider({ name: "wmill" }),
}),
)
.command("completions", new CompletionsCommand());
);
if (Number.parseInt(VERSION.replace("v", "").replace(".", "")) > 1700) {
command = command

View File

@@ -11,7 +11,6 @@ import {
Table,
} from "./deps.ts";
import { Any, array, decoverto, model, property } from "./decoverto.ts";
import { writeAllSync } from "https://deno.land/std@0.176.0/streams/mod.ts";
@model()
export class ScriptFile {
@@ -281,27 +280,50 @@ async function list(opts: GlobalOptions & { showArchived?: boolean }) {
.render();
}
export async function resolve(input: string): Promise<Record<string, any>> {
if (!input) {
throw new Error("No data given");
export async function resolve(inputs: string[]): Promise<Record<string, any>> {
let result = {};
if (!inputs) {
return result;
}
if (input == "@-") {
input = new TextDecoder().decode(await readAll(Deno.stdin));
} if (input[0] == "@") {
input = await Deno.readTextFile(input.substring(1));
}
try {
return JSON.parse(input);
} catch (e) {
console.error("Impossible to parse input as JSON", input)
throw e
for (const input of inputs) {
let data: string;
if (input.startsWith("@")) {
if (input == "@-") {
data = new TextDecoder().decode(await readAll(Deno.stdin));
} else {
data = await Deno.readTextFile(input.substring(1));
}
} else {
if (input.startsWith("{")) {
data = input;
} else {
const key = input.split("=", 1)[0];
const value = input.substring(key.length + 1);
let o;
try {
o = JSON.parse(value);
} catch {
o = value;
}
data = JSON.stringify(Object.fromEntries([[key, o]]));
}
}
let jsonObj;
try {
jsonObj = JSON.parse(data);
} catch {
jsonObj = data;
}
result = { ...result, ...jsonObj };
}
return result;
}
async function run(
opts: GlobalOptions & {
data?: string;
input: string[];
silent: boolean;
},
path: string,
@@ -309,8 +331,7 @@ async function run(
const workspace = await resolveWorkspace(opts);
await requireLogin(opts);
const input = opts.data ? await resolve(opts.data) : {};
const input = await resolve(opts.input);
const id = await JobService.runScriptByPath({
workspace: workspace.workspaceId,
path,
@@ -343,9 +364,7 @@ export async function track_job(workspace: string, id: string) {
const result = await JobService.getCompletedJob({ workspace, id });
console.log(result.logs);
console.log()
console.log(colors.bold.underline.green("Job Completed"));
console.log()
return;
} catch {
/* ignore */
@@ -384,7 +403,7 @@ export async function track_job(workspace: string, id: string) {
}
if (updates.new_logs) {
writeAllSync(Deno.stdout, new TextEncoder().encode(updates.new_logs));
console.log(updates.new_logs);
logOffset += updates.new_logs.length;
}
@@ -407,15 +426,12 @@ export async function track_job(workspace: string, id: string) {
if ((final_job.logs?.length ?? -1) > logOffset) {
console.log(final_job.logs!.substring(logOffset));
}
console.log("\n")
if (final_job.success) {
console.log(colors.bold.underline.green("Job Completed"));
} else {
console.log(colors.bold.underline.red("Job Completed"));
}
console.log()
} catch {
console.log("Job appears to have completed, but no data can be retrieved");
}
@@ -450,8 +466,8 @@ const command = new Command()
.command("run", "run a script by path")
.arguments("<path:string>")
.option(
"-d --data <data:string>",
"Inputs specified as a JSON string or a file using @<filename> or stdin using @-.",
"-i --input [inputs...:string]",
"Inputs specified as JSON objects or simply as <name>=<value>. Supports file inputs using @<filename> and stdin using @- these also need to be formatted as JSON. Later inputs override earlier ones.",
)
.option(
"-s --silent",

View File

@@ -9,7 +9,7 @@
"lock": "",
"path": null,
"type": "rawscript",
"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",
"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",
"language": "deno",
"input_transforms": {
"x": {

View File

@@ -9,11 +9,9 @@ import {
Input,
setClient,
Table,
UserService,
WorkspaceService,
} from "./deps.ts";
import { decoverto, model, property } from "./decoverto.ts";
import { requireLogin } from "./context.ts";
@model()
export class Workspace {
@@ -310,18 +308,12 @@ async function remove(_opts: GlobalOptions, name: string) {
await removeWorkspace(name, false, _opts);
}
async function whoami(_opts: GlobalOptions) {
await requireLogin(_opts)
console.log(await UserService.globalWhoami())
}
const command = new Command()
.description("workspace related commands")
.action(list as any)
.command("switch")
.complete("workspace", async () => (await allWorkspaces()).map((x) => x.name))
.description("Switch to another workspace")
.arguments("<workspace_name:string:workspace>")
.arguments("<workspace_name:string>")
.action(switchC as any)
.command("add")
.description("Add a workspace")
@@ -342,9 +334,6 @@ const command = new Command()
.command("remove")
.description("Remove a workspace")
.arguments("<workspace_name:string>")
.action(remove as any)
.command("whoami")
.description("Show the currently active user")
.action(whoami as any);
.action(remove as any);
export default command;

View File

@@ -4,9 +4,8 @@ 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/

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "windmill",
"version": "1.72.0",
"version": "1.69.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",
@@ -15,7 +15,7 @@
"test": "playwright test --config=tests-out/playwright.config.js"
},
"devDependencies": {
"@playwright/test": "^1.31.1",
"@playwright/test": "^1.29.2",
"@sveltejs/adapter-static": "^1.0.0",
"@sveltejs/kit": "^1.0.0-next.589",
"@sveltejs/package": "^1.0.2",
@@ -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.6",
"@windmill-labs/svelte-grid": "^5.1.3",
"@windmill-labs/svelvet": "^4.0.20",
"@zerodevx/svelte-toast": "^0.8.1",
"autoprefixer": "^10.4.13",
@@ -34,7 +34,6 @@
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-svelte3": "^4.0.0",
"ol": "^7.2.2",
"openapi-typescript-codegen": "^0.23.0",
"path-browserify": "^1.0.1",
"postcss": "^8.4.18",
@@ -67,13 +66,11 @@
"@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",
@@ -83,7 +80,7 @@
"svelte-autosize": "^1.0.1",
"svelte-chartjs": "^3.1.0",
"svelte-portal": "^2.2.0",
"svelte-select": "^5.3.1",
"svelte-select": "^5.0.2",
"tailwind-merge": "^1.9.1",
"vscode-ws-jsonrpc": "^2.0.1"
},

View File

@@ -44,10 +44,9 @@ declare module '@windmill-labs/svelte-grid' {
fastStart?: boolean
throttleUpdate?: number
throttleResize?: number
onTopId?: string
scroller?: undefined
sensor?: number
parentWidth?: number
}
export interface Slots<T> {
@@ -61,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

@@ -2,10 +2,9 @@
import { Highlight } from 'svelte-highlight'
import { json } from 'svelte-highlight/languages'
import TableCustom from './TableCustom.svelte'
import { copyToClipboard, truncate } from '$lib/utils'
import { Button, Drawer, DrawerContent } from './common'
import { truncate } from '$lib/utils'
import { Button } from './common'
import autosize from 'svelte-autosize'
import { ClipboardCopy } from 'lucide-svelte'
export let result: any
export let requireHtmlApproval = false
@@ -87,36 +86,16 @@
return 'json'
}
let payload = ''
let jsonViewer: Drawer
</script>
<Drawer bind:this={jsonViewer} size="900px">
<DrawerContent title="Expanded Result" on:close={jsonViewer.closeDrawer}>
<svelte:fragment slot="actions">
<Button
on:click={() => copyToClipboard(JSON.stringify(result, null, 4))}
color="light"
size="xs"
>
<div class="flex gap-2 items-center">Copy to clipboard <ClipboardCopy /> </div>
</Button>
</svelte:fragment>
<Highlight language={json} code={JSON.stringify(result, null, 4).replace(/\\n/g, '\n')} />
</DrawerContent>
</Drawer>
<div class="inline-highlight">
{#if result != undefined}
{#if resultKind && resultKind != 'json'}
<div class="mb-2 text-gray-500 text-sm bg-gray-50/20">
as JSON&nbsp;<input type="checkbox" bind:checked={forceJson} /></div
>{/if}{#if typeof result == 'object' && Object.keys(result).length > 0}<div
class="mb-2 min-w-[400px] text-sm text-gray-700 relative"
>The result keys are: <b>{truncate(Object.keys(result).join(', '), 50)}</b>
<div class="text-gray-500 text-sm absolute top-0 right-2">
<button on:click={jsonViewer.openDrawer}>Expand JSON</button>
</div></div
class="mb-2 text-sm text-gray-700"
>The result keys are: <b>{truncate(Object.keys(result).join(', '), 50)}</b></div
>{/if}{#if !forceJson && resultKind == 'table-col'}<div
class="grid grid-flow-col-dense border border-gray-200 rounded-md "
>
@@ -244,8 +223,10 @@
><a rel="noreferrer" target="_blank" href={result['approvalPage']}>Approval Page</a></div
>
</div>
{:else}
<Highlight language={json} code={JSON.stringify(result, null, 4).replace(/\\n/g, '\n')} />
{:else}<Highlight
language={json}
code={JSON.stringify(result, null, 4).replace(/\\n/g, '\n')}
/>
{/if}
{:else}
<div class="text-gray-500 text-sm">No result</div>

View File

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

View File

@@ -13,7 +13,6 @@
import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte'
import { OFFSET } from './CronInput.svelte'
import FlowGraphViewer from './FlowGraphViewer.svelte'
import ScriptEditorDrawer from './flows/content/ScriptEditorDrawer.svelte'
import FlowEditor from './flows/FlowEditor.svelte'
import { flowStateStore } from './flows/flowState'
import { flowStore } from './flows/flowStore'
@@ -113,6 +112,7 @@
await createSchedule(flow.path)
}
}
sendUserToast(`Flow saved at ${$flowStore.path}`)
goto(`/flows/get/${$flowStore.path}?workspace_id=${$workspaceStore}`)
}
@@ -145,7 +145,6 @@
const scheduleStore = writable<Schedule>({ args: {}, cron: '', enabled: false })
const previewArgsStore = writable<Record<string, any>>(initialArgs)
const scriptEditorDrawer = writable<ScriptEditorDrawer | undefined>(undefined)
function select(selectedId: string) {
selectedIdStore.set(selectedId)
@@ -155,8 +154,7 @@
selectedId: selectedIdStore,
schedule: scheduleStore,
select,
previewArgs: previewArgsStore,
scriptEditorDrawer
previewArgs: previewArgsStore
})
async function loadSchedule() {
@@ -183,7 +181,6 @@
</script>
{#if !$userStore?.operator}
<ScriptEditorDrawer bind:this={$scriptEditorDrawer} />
<UnsavedConfirmationModal />
<Drawer bind:this={flowViewer} size="75%">

View File

@@ -97,9 +97,7 @@
class="w-full border-r border-b border-t border-gray-400 min-h-[150px] p-2 overflow-auto hidden sm:block"
>
{#if stepDetail == undefined}
<SchemaViewer schema={flow?.schema} />
<span class="font-black text-lg w-full my-4 mt-14">
<span class="font-black text-lg w-full my-4">
<span>Click on a step to see its details</span>
</span>
{:else if stepDetail == 'Input'}

View File

@@ -12,9 +12,9 @@
<div
class:border={!noBorder}
class="grid {!col ? 'grid-cols-2' : 'grid-rows-2'} shadow border-gray-400 h-full max-h-screen"
class="grid {!col ? 'grid-cols-2' : 'grid-rows-2'} shadow border-gray-400 h-full"
>
<div class="bg-white {col ? '' : 'max-h-80'} h-full p-1 overflow-auto relative">
<div class="bg-white max-h-80 h-full p-1 overflow-auto relative">
<span class="text-gray-500">Result</span>
{#if result}
<DisplayResult {result} />
@@ -24,7 +24,7 @@
<div class="text-gray-400">No result (result is undefined)</div>
{/if}
</div>
<div class="overflow-auto {col ? '' : 'max-h-80'} h-full relative">
<div class="overflow-auto max-h-80 h-full relative">
<LogViewer content={logs ?? ''} isLoading={false} />
</div>
</div>

View File

@@ -21,6 +21,7 @@
export let jobId: string | undefined = undefined
export let job: Job | undefined = undefined
let isValid: boolean = true
let isRunning: boolean = false
let jobProgressReset: () => void
@@ -104,6 +105,7 @@
{#if isRunning}
<Button
disabled={!isValid}
color="red"
on:click={async () => {
isRunning = false
@@ -130,6 +132,7 @@
color="blue"
size="sm"
btnClasses="w-full max-w-lg"
disabled={!isValid}
on:click={() => runPreview($previewArgs)}
>
Test flow <Kbd class="ml-2">Ctrl+Enter</Kbd>
@@ -146,13 +149,14 @@
</div>
<FlowProgressBar {job} bind:reset={jobProgressReset} />
<div class="overflow-y-auto grow divide-y divide-gray-600 pr-4">
<div class="overflow-y-auto grow divide-y divide-gray-600 ">
<div class="max-h-1/2 overflow-auto border-b border-gray-700">
<SchemaForm
noVariablePicker
compact
class="py-4 max-w-3xl"
schema={$flowStore.schema}
bind:isValid
bind:args={$previewArgs}
/>
</div>

View File

@@ -96,7 +96,7 @@
localFlowModuleStates?.[innerModules?.[i - 1]?.id ?? '']?.type ==
FlowStatusModule.type.SUCCESS
) {
localFlowModuleStates[mod.id ?? ''] = { type: mod.type, args: job?.args }
localFlowModuleStates[mod.id ?? ''] = { type: mod.type }
} else if (
mod.type === FlowStatusModule.type.WAITING_FOR_EXECUTOR &&
localFlowModuleStates[mod.id ?? '']?.scheduled_for == undefined
@@ -109,8 +109,7 @@
type: mod.type,
scheduled_for: 'scheduled for ' + displayDate(job?.['scheduled_for'], true),
job_id: job?.id,
parent_module: mod['parent_module'],
args: job?.args
parent_module: mod['parent_module']
}
})
}
@@ -330,12 +329,10 @@
type: FlowStatusModule.type.IN_PROGRESS,
logs: e.detail.logs,
job_id: e.detail.id,
args: e.detail.args,
iteration_total: flowJobIds?.flowJobs.length
}
} else {
localFlowModuleStates[flowJobIds.moduleId] = {
args: e.detail.args,
type: e.detail.success
? FlowStatusModule.type.SUCCESS
: FlowStatusModule.type.FAILURE,
@@ -400,12 +397,10 @@
localFlowModuleStates[mod.id] = {
type: FlowStatusModule.type.IN_PROGRESS,
logs: e.detail.logs,
args: e.detail.args,
parent_module: mod['parent_module']
}
} else {
localFlowModuleStates[mod.id] = {
args: e.detail.args,
type: e.detail.success
? FlowStatusModule.type.SUCCESS
: FlowStatusModule.type.FAILURE,
@@ -502,10 +497,6 @@
</div>
{/if}
</div>
<div class="px-1 border-b border-black">
<JobArgs args={node.args} />
</div>
<FlowJobResult
loading={job['running'] == true}
noBorder

View File

@@ -82,10 +82,16 @@
}
function connectProperty(rawValue: string) {
arg.expr = getDefaultExpr(undefined, previousModuleId, rawValue)
arg.type = 'javascript'
propertyType = 'javascript'
monaco?.setCode(arg.expr)
if (isStaticTemplate(inputCat)) {
arg.value = `\$\{${rawValue}}`
setPropertyType(arg.value)
monacoTemplate?.setCode(arg.value)
} else {
arg.expr = getDefaultExpr(undefined, previousModuleId, rawValue)
arg.type = 'javascript'
propertyType = 'javascript'
monaco?.setCode(arg.expr)
}
}
function onFocus() {

View File

@@ -86,7 +86,6 @@
detailed={false}
topButton
bind:args={stepArgs}
isFlow={false}
/>
{#if testIsLoading}
<Button on:click={testJobLoader?.cancelJob} btnClasses="w-full mt-4" color="red" size="sm">

View File

@@ -277,19 +277,15 @@
folderCreated = undefined
}}
>
{#if !folderCreated}
<div class="flex flex-row">
<input class="mr-2" placeholder="New folder name" bind:value={newFolderName} />
<Button
size="md"
startIcon={{ icon: faPlus }}
disabled={!newFolderName}
on:click={addFolder}
>
New&nbsp;folder
</Button>
</div>
{:else}
<div class="flex flex-row">
<input class="mr-2" placeholder="New folder name" bind:value={newFolderName} />
<Button size="md" startIcon={{ icon: faPlus }} disabled={!newFolderName} on:click={addFolder}>
New&nbsp;folder
</Button>
</div>
{#if folderCreated}
<div class="mt-8" />
<FolderEditor name={folderCreated} />
{/if}
</DrawerContent>

View File

@@ -8,7 +8,6 @@
import Select from 'svelte-select'
import AppConnect from './AppConnect.svelte'
import ResourceEditor from './ResourceEditor.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../defaults'
const dispatch = createEventDispatcher()
let resources: Resource[] = []
@@ -60,13 +59,12 @@
<div class="flex flex-row gap-x-1 w-full">
<Select
listAutoWidth={false}
--height="34px"
value={collection.find((x) => x.value == value)}
bind:justValue={value}
items={collection}
class="text-clip grow min-w-0"
placeholder="{resourceType} resource"
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles}
/>
{#if value && value != ''}
<Button variant="border" size="xs" on:click={() => resourceEditor?.initEdit?.(value ?? '')}>

View File

@@ -49,7 +49,6 @@
export let loading = false
export let noVariablePicker = false
export let viewCliRun = false
export let isFlow: boolean
export let args: Record<string, any> = decodeArgs($page.url.searchParams.get('args') ?? undefined)
@@ -65,9 +64,9 @@
let scheduledForStr: string | undefined
let invisible_to_owner: false
$: cliCommand = `wmill ${isFlow ? 'flow' : 'script'} run ${runnable?.path} -d '${JSON.stringify(
args
)}'`
$: cliCommand = `wmill ${runnable?.kind} run ${runnable?.path} ${Object.entries(args)
.map(([k, v]) => `-i ${k}=${JSON.stringify(v)}`)
.join(' ')}`
</script>
<div class="max-w-6xl">
@@ -146,7 +145,7 @@
</Button>
</div>
{#if viewOptions}
<div transition:slide|local class="mt-6">
<div transition:slide class="mt-6">
<div class="border rounded-md p-3 pt-4">
<div class="flex flex-row items-end">
<div class="w-max md:w-2/3 mt-2 mb-1">
@@ -214,14 +213,14 @@
<div class="my-10" />
<Button
color="light"
size="xs"
size="sm"
endIcon={{ icon: viewCliOptions ? faChevronUp : faChevronDown }}
on:click={() => (viewCliOptions = !viewCliOptions)}
>
Run it from the CLI
</Button>
{#if viewCliOptions}
<div transition:slide|local class="mt-2 px-4 pt-2">
<div transition:slide class="mt-2 px-4 pt-2">
<InlineCodeCopy content={cliCommand} />
<CliHelpBox />
</div>

View File

@@ -4,6 +4,7 @@
import { workspaceStore } from '$lib/stores'
import { allTrue } from '$lib/utils'
import { faPlus } from '@fortawesome/free-solid-svg-icons'
import { slide } from 'svelte/transition'
import ArgInput from './ArgInput.svelte'
import { Button } from './common'
import InputTransformForm from './InputTransformForm.svelte'
@@ -68,8 +69,8 @@
<div class="w-full {clazz} {flexWrap ? 'flex flex-row flex-wrap gap-x-6 gap-y-2' : ''}">
{#if keys.length > 0}
{#each keys as argName, i (argName)}
{#if (!filter || filter.includes(argName)) && Object.keys(schema.properties ?? {}).includes(argName)}
<div>
{#if !filter || filter.includes(argName)}
<div transition:slide|local>
{#if inputTransform}
<InputTransformForm
{previousModuleId}
@@ -83,7 +84,7 @@
bind:pickForField
{noDynamicToggle}
/>
{:else if typeof args == 'object' && schema?.properties[argName]}
{:else if typeof args == 'object'}
<ArgInput
autofocus={i == 0 && autofocus}
label={argName}

View File

@@ -24,7 +24,6 @@
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],
@@ -83,6 +82,7 @@
kind: script.kind
}
})
sendUserToast(`New script created at hash ${newHash}`)
history.replaceState(history.state, '', `/scripts/edit/${newHash}?step=2`)
goto(`/scripts/get/${newHash}?workspace_id=${$workspaceStore}`)
} catch (error) {
@@ -214,13 +214,7 @@
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'}
@@ -234,7 +228,6 @@
template = 'script'
initContent(lang, script.kind, template)
}}
disabled={lockedLanguage}
>
<LanguageIcon {lang} /><span class="ml-2 py-4">{label}</span>
</Button>
@@ -244,7 +237,6 @@
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'

View File

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

View File

@@ -11,7 +11,6 @@
import { Button, Drawer, DrawerContent } from './common'
import HighlightCode from './HighlightCode.svelte'
import FlowPathViewer from './flows/content/FlowPathViewer.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../defaults'
export let initialPath: string | undefined = undefined
export let scriptPath: string | undefined = undefined
@@ -88,8 +87,6 @@
bind:justValue={scriptPath}
{items}
placeholder="Pick a {itemKind}"
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles}
/>
{/if}

View File

@@ -110,10 +110,6 @@
}
}
export function focus() {
editor?.focus()
}
let width = 0
async function loadMonaco() {
model = meditor.createModel(code, lang, mUri.parse(uri))

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { twMerge } from 'tailwind-merge'
export let options: {
left?: string
@@ -8,8 +7,6 @@
} = {}
export let checked: boolean = false
export let disabled = false
export let textClass = ''
export let textStyle = ''
export let size: 'sm' | 'xs' = 'sm'
const id = (Math.random() + 1).toString(36).substring(10)
@@ -25,13 +22,7 @@
>
{#if Boolean(options?.left)}
<span
class={twMerge(
'ml-2 font-medium duration-200',
disabled ? 'text-gray-500' : 'text-gray-900',
size === 'xs' ? 'text-xs' : 'text-sm',
textClass
)}
style={textStyle}
class="mr-2 text-sm font-medium duration-200 {disabled ? 'text-gray-600' : 'text-gray-900'}"
>
{options?.left}
</span>
@@ -60,13 +51,9 @@
</div>
{#if Boolean(options?.right)}
<span
class={twMerge(
'ml-2 font-medium duration-200',
disabled ? 'text-gray-500' : 'text-gray-900',
size === 'xs' ? 'text-xs' : 'text-sm',
textClass
)}
style={textStyle}
class="ml-2 text-sm font-medium duration-200
{disabled ? 'text-gray-500' : 'text-gray-900'}
{size === 'xs' ? 'text-xs' : 'text-sm'}"
>
{options?.right}
</span>

View File

@@ -39,7 +39,6 @@
export function closeDrawer() {
drawer?.closeDrawer()
const index = $page.url.href.lastIndexOf('#')
if (index === -1) return
const hashRemoved = $page.url.href.slice(0, index)
goto(hashRemoved)
}

View File

@@ -10,7 +10,6 @@
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import { loadIcon } from '../icon'
import { twMerge } from 'tailwind-merge'
import { goto } from '$app/navigation'
export let id: string
export let componentInput: AppInput | undefined
@@ -33,8 +32,7 @@
let runnableComponent: RunnableComponent
let disabled: boolean | undefined = undefined
let fillContainer: boolean | undefined = undefined
let gotoUrl: string | undefined = undefined
let gotoNewTab: boolean | undefined = undefined
let goto: string | undefined = undefined
let isLoading: boolean = false
let ownClick: boolean = false
@@ -89,7 +87,7 @@
</script>
<InputValue {id} input={configuration.label} bind:value={labelValue} />
<InputValue {id} input={configuration.goto} bind:value={gotoUrl} />
<InputValue {id} input={configuration.goto} bind:value={goto} />
<InputValue {id} input={configuration.color} bind:value={color} />
<InputValue {id} input={configuration.size} bind:value={size} />
<InputValue {id} input={configuration.beforeIcon} bind:value={beforeIcon} />
@@ -97,23 +95,22 @@
<InputValue {id} input={configuration.triggerOnAppLoad} bind:value={triggerOnAppLoad} />
<InputValue
row={extraQueryParams['row']}
{id}
input={configuration.disabled}
bind:value={disabled}
bind:error={errors.disabled}
/>
<InputValue {id} input={configuration.fillContainer} bind:value={fillContainer} />
<InputValue {id} input={configuration.gotoNewTab} bind:value={gotoNewTab} />
<RunnableWrapper
flexWrap
bind:runnableComponent
{componentInput}
bind:componentInput
{id}
{extraQueryParams}
autoRefresh={false}
goto={gotoUrl}
{gotoNewTab}
{goto}
>
<AlignWrapper {noWFull} {horizontalAlignment} {verticalAlignment}>
{#if errorsMessage}
@@ -138,18 +135,7 @@
e?.stopPropagation()
e?.preventDefault()
ownClick = true
if (!runnableComponent) {
if (gotoUrl) {
if (gotoNewTab) {
window.open(gotoUrl, '_blank')
} else {
goto(gotoUrl)
}
}
} else {
await runnableComponent?.runComponent()
}
await runnableComponent?.runComponent()
if (recomputeIds) {
recomputeIds.forEach((id) => {

View File

@@ -5,8 +5,7 @@
import { Icon } from 'svelte-awesome'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type RunnableComponent from '../helpers/RunnableComponent.svelte'
@@ -18,12 +17,10 @@
export let recomputeIds: string[] | undefined = undefined
export let extraQueryParams: Record<string, any> = {}
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let customCss: ComponentCustomCSS<'container' | 'button'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app, runnableComponents, worldStore, stateId } =
getContext<AppEditorContext>('AppEditorContext')
const { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
let labelValue: string = 'Default label'
let color: ButtonType.Color
@@ -34,8 +31,7 @@
let isLoading: boolean = false
$: noInputs =
$stateId != undefined &&
(componentInput?.type != 'runnable' || Object.keys(componentInput?.fields ?? {}).length == 0)
componentInput?.type != 'runnable' || Object.keys(componentInput?.fields ?? {}).length == 0
$: outputs = $worldStore?.outputsById[id] as {
result: Output<Array<any>>
@@ -51,8 +47,6 @@
isLoading = value
}
})
$: css = concatCustomCss($app.css?.formcomponent, customCss)
</script>
<InputValue {id} input={configuration.goto} bind:value={goto} />
@@ -61,21 +55,18 @@
<InputValue {id} input={configuration.size} bind:value={size} />
<RunnableWrapper
defaultUserInput
bind:runnableComponent
{componentInput}
bind:componentInput
{id}
{goto}
{extraQueryParams}
autoRefresh={false}
forceSchemaDisplay={true}
runnableClass="!block"
runnableStyle={css?.container.style}
>
<AlignWrapper {horizontalAlignment}>
<div
class="flex flex-col gap-2 px-4 w-full {css?.container?.class ?? ''}"
style={css?.container?.style ?? ''}
>
<div class="flex flex-col gap-2 px-4 w-full">
<div>
{#if noInputs}
<div class="text-gray-600 italic text-sm my-4">
@@ -93,8 +84,7 @@
{#if !noInputs}
<Button
loading={isLoading}
btnClasses="my-1 {css?.button?.class ?? ''}"
style={css?.button?.style ?? ''}
btnClasses="my-1"
on:pointerdown={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))

View File

@@ -5,14 +5,13 @@
import { Icon } from 'svelte-awesome'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type RunnableComponent from '../helpers/RunnableComponent.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import Portal from 'svelte-portal'
import Modal from '$lib/components/common/modal/Modal.svelte'
import { concatCustomCss } from '../../utils'
export let id: string
export let componentInput: AppInput | undefined
@@ -21,11 +20,10 @@
export let extraQueryParams: Record<string, any> = {}
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'button' | 'popup'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app, runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
let labelValue: string = 'Default label'
let color: ButtonType.Color
@@ -37,8 +35,6 @@
let ownClick: boolean = false
let errors: Record<string, string> = {}
let open: boolean = false
$: errorsMessage = Object.values(errors)
.filter((x) => x != '')
.join('\n')
@@ -66,13 +62,14 @@
$: loading = isLoading && ownClick
$: css = concatCustomCss($app?.css?.formbuttoncomponent, customCss)
let open: boolean = false
</script>
<InputValue {id} input={configuration.label} bind:value={labelValue} />
<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}
@@ -83,8 +80,6 @@
<Modal
{open}
title={labelValue}
class={css?.popup.class}
style={css?.popup.style}
on:canceled={() => {
open = false
}}
@@ -93,8 +88,9 @@
}}
>
<RunnableWrapper
defaultUserInput
bind:runnableComponent
{componentInput}
bind:componentInput
{id}
{extraQueryParams}
autoRefresh={false}
@@ -153,8 +149,6 @@
{disabled}
{size}
{color}
btnClasses={css?.button?.class ?? ''}
style={css?.button?.style ?? ''}
on:click={(e) => {
open = true
}}

View File

@@ -15,18 +15,13 @@
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
import { concatCustomCss } from '../../utils'
import { getContext } from 'svelte'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
ChartJS.register(
Title,
@@ -82,21 +77,17 @@
}
]
}
$: css = concatCustomCss($app.css?.barchartcomponent, customCss)
</script>
<InputValue {id} input={configuration.theme} bind:value={theme} />
<InputValue {id} input={configuration.line} bind:value={lineChart} />
<RunnableWrapper flexWrap autoRefresh {componentInput} {id} bind:initializing bind:result>
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
{#if lineChart}
<Line {data} options={lineOptions} />
{:else}
<Bar {data} options={barOptions} />
{/if}
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
{#if lineChart}
<Line {data} options={lineOptions} />
{:else}
<Bar {data} options={barOptions} />
{/if}
</div>
{/if}
</RunnableWrapper>

View File

@@ -3,11 +3,7 @@
import { getContext } from 'svelte'
import { twMerge } from 'tailwind-merge'
import type { AppInput } from '../../inputType'
import {
IS_APP_PUBLIC_CONTEXT_KEY,
type AppEditorContext,
type ComponentCustomCSS
} from '../../types'
import { IS_APP_PUBLIC_CONTEXT_KEY, type AppEditorContext, type ComponentCustomCSS } from '../../types'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
@@ -22,23 +18,19 @@
export const staticOutputs: string[] = ['result', 'loading']
</script>
<RunnableWrapper flexWrap {componentInput} {id} bind:initializing bind:result>
<div
class={twMerge(
'w-full border-b px-2 text-xs p-1 font-semibold bg-gray-500 text-white rounded-t-sm',
$app.css?.['displaycomponent']?.['header']?.class,
customCss?.header?.class
)}
>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
<div class={twMerge(
'w-full border-b px-2 text-xs p-1 font-semibold bg-gray-500 text-white rounded-t-sm',
$app.css?.['displaycomponent']?.['header']?.class,
customCss?.header?.class
)}>
Results
</div>
<div
class={twMerge(
'p-2',
$app.css?.['displaycomponent']?.['container']?.class,
customCss?.container?.class
)}
>
<div class={twMerge(
'p-2',
$app.css?.['displaycomponent']?.['container']?.class,
customCss?.container?.class
)}>
<DisplayResult {result} {requireHtmlApproval} />
</div>
</RunnableWrapper>

View File

@@ -1,23 +1,16 @@
<script lang="ts">
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['result', 'loading']
const { app } = getContext<AppEditorContext>('AppEditorContext')
let result: string | undefined = undefined
let h: number | undefined = undefined
let w: number | undefined = undefined
$: css = concatCustomCss($app.css?.htmlcomponent, customCss)
</script>
<div
@@ -28,12 +21,12 @@
bind:clientHeight={h}
bind:clientWidth={w}
>
<RunnableWrapper autoRefresh flexWrap {componentInput} {id} bind:initializing bind:result>
<RunnableWrapper autoRefresh flexWrap bind:componentInput {id} bind:initializing bind:result>
{#key result}
<iframe
frameborder="0"
style="height: {h}px; width: {w}px; {css?.container?.style ?? ''}"
class="p-0 {css?.container?.class ?? ''}"
style="height: {h}px; width: {w}px"
class="p-0"
title="sandbox"
srcdoc={result
? '<scr' + `ipt type="application/javascript" src="/tailwind.js"></script>` + result

View File

@@ -1,9 +1,6 @@
<script lang="ts">
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import { AlignWrapper, InputValue } from '../helpers'
import { AlignWrapper, InputValue, RunnableWrapper } from '../helpers'
import { loadIcon } from '../icon'
export let id: string
@@ -11,9 +8,6 @@
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let configuration: Record<string, AppInput>
export const staticOutputs: string[] = []
export let customCss: ComponentCustomCSS<'container' | 'icon'> | undefined = undefined
const { app } = getContext<AppEditorContext>('AppEditorContext')
let icon: string | undefined = undefined
let size: number
@@ -28,8 +22,6 @@
iconComponent = await loadIcon(icon)
}
}
$: css = concatCustomCss($app.css?.iconcomponent, customCss)
</script>
<InputValue {id} input={configuration.icon} bind:value={icon} />
@@ -37,20 +29,13 @@
<InputValue {id} input={configuration.color} bind:value={color} />
<InputValue {id} input={configuration.strokeWidth} bind:value={strokeWidth} />
<AlignWrapper
{horizontalAlignment}
{verticalAlignment}
class={css?.container?.class ?? ''}
style={css?.container?.style ?? ''}
>
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
{#if iconComponent}
<svelte:component
this={iconComponent}
size={size || 24}
color={color || 'currentColor'}
strokeWidth={strokeWidth || 2}
class={css?.icon?.class ?? ''}
style={css?.icon?.style ?? ''}
/>
{/if}
</AlignWrapper>

View File

@@ -1,41 +1,34 @@
<script lang="ts">
import { getContext } from 'svelte'
import { twMerge } from 'tailwind-merge'
import type { staticValues } from '../../editor/componentsPanel/componentStaticValues'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
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>
export const staticOutputs: string[] = ['loading']
export let customCss: ComponentCustomCSS<'image'> | undefined = undefined
const { app } = getContext<AppEditorContext>('AppEditorContext')
const fit: Record<FitOption, string> = {
cover: 'object-cover',
contain: 'object-contain',
fill: 'object-fill'
fill: 'object-fill',
}
let source: string | undefined = undefined
let imageFit: FitOption | undefined = undefined
let altText: string | undefined = undefined
$: css = concatCustomCss($app.css?.imagecomponent, customCss)
let customStyles: string | undefined = undefined
</script>
<InputValue {id} input={configuration.source} bind:value={source} />
<InputValue {id} input={configuration.imageFit} bind:value={imageFit} />
<InputValue {id} input={configuration.altText} bind:value={altText} />
<InputValue {id} input={configuration.customStyles} bind:value={customStyles} />
<img
on:pointerdown|preventDefault
src={source}
alt={altText}
style={css?.image?.style ?? ''}
class={twMerge(`w-full h-full ${fit[imageFit || 'cover']}`, css?.image?.class ?? '')}
/>
style={customStyles}
class="w-full h-full {fit[imageFit || 'cover']}"
>

View File

@@ -1,222 +0,0 @@
<script lang="ts">
import { getContext, onMount } from 'svelte'
import { concatCustomCss } from '../../utils'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { InputValue } from '../helpers'
import { twMerge } from 'tailwind-merge'
import { Map, View, Feature } from 'ol'
import { useGeographic } from 'ol/proj'
import { OSM, Vector as VectorSource } from 'ol/source'
import { Vector as VectorLayer, Tile as TileLayer } from 'ol/layer'
import { Point } from 'ol/geom'
import { defaults as defaultControls } from 'ol/control'
import { findGridItem } from '../../editor/appUtils'
import type { Output } from '../../rx'
interface Marker {
lon: number
lat: number
title?: string
radius?: number
color?: string
strokeWidth?: number
strokeColor?: string
}
const LAYER_NAME = {
MARKER: 'Marker'
} as const
export let id: string
export let configuration: Record<string, AppInput>
export const staticOutputs: string[] = ['mapRegion']
export let customCss: ComponentCustomCSS<'map'> | undefined = undefined
const { app, worldStore, selectedComponent, connectingInput, focusedGrid, mode } =
getContext<AppEditorContext>('AppEditorContext')
$: outputs = $worldStore?.outputsById[id] as {
mapRegion: Output<{
topLeft: { lat: number; lon: number }
bottomRight: { lat: number; lon: number }
}>
}
let map: Map
let mapElement: HTMLDivElement
let longitude: number | undefined = undefined
let latitude: number | undefined = undefined
let zoom: number | undefined = undefined
// If string, it's a JSON file read as text
let markers: Marker[] | string | undefined = undefined
$: if (map && longitude && latitude) {
map.getView().setCenter([longitude, latitude])
}
$: if (map && zoom) {
map.getView().setZoom(zoom)
}
$: if (map && markers) {
updateMarkers()
}
function selectComponent() {
if (!$connectingInput.opened) {
$selectedComponent = id
$focusedGrid = undefined
}
}
function getLayersByName(name: keyof typeof LAYER_NAME) {
return map
.getLayers()
.getArray()
.filter((l) => l.getProperties().name === LAYER_NAME[name])
}
function getMarkerArray(): Marker[] | undefined {
let array: Marker[] | undefined = undefined
if (typeof markers === 'string') {
try {
array = JSON.parse(markers)
} catch (e) {
return undefined
}
} else {
array = markers
}
return array?.filter((m) => !isNaN(+m.lat) && !isNaN(+m.lon))
}
function createMarkerLayers() {
const markerArray = getMarkerArray()
return markerArray?.map((m) => {
return new VectorLayer({
properties: {
name: LAYER_NAME.MARKER
},
source: new VectorSource({
features: [
new Feature({
geometry: new Point([+m.lon, +m.lat]),
name: m.title
})
]
}),
style: {
'circle-radius': m.radius ?? 7,
'circle-fill-color': m.color ?? '#dc2626',
'circle-stroke-width': m.strokeWidth ?? 3,
'circle-stroke-color': m.strokeColor ?? '#fca5a5'
}
})
})
}
function updateMarkers() {
const layers = getLayersByName('MARKER')
if (layers?.length) {
layers.forEach((l) => map.removeLayer(l))
}
createMarkerLayers()?.forEach((l) => map.addLayer(l))
}
onMount(() => {
useGeographic()
map = new Map({
target: mapElement,
layers: [
new TileLayer({
source: new OSM()
}),
...(createMarkerLayers() || [])
],
view: new View({
center: [longitude ?? 0, latitude ?? 0],
zoom: zoom ?? 2
}),
controls: defaultControls({
attribution: false
})
})
updateRegionOutput()
})
$: css = concatCustomCss($app.css?.mapcomponent, customCss)
$: gridItem = findGridItem($app, id)
function updateRegionOutput() {
if (map) {
let extent = map.getView().calculateExtent(map.getSize())
const [left, bottom, right, top] = extent
if (outputs?.mapRegion) {
outputs.mapRegion.set({
topLeft: { lat: top, lon: left },
bottomRight: { lat: bottom, lon: right }
})
}
}
}
function handleSyncRegion() {
if (!map || !gridItem) {
return
}
const z = map.getView().getZoom()
updateRegionOutput()
if (z) {
gridItem.data.configuration.zoom.value = z
}
const center = map.getView().getCenter()
if (!center) {
return
}
if (gridItem) {
gridItem.data.configuration.longitude.value = center[0]
gridItem.data.configuration.latitude.value = center[1]
}
}
</script>
<InputValue {id} input={configuration.longitude} bind:value={longitude} />
<InputValue {id} input={configuration.latitude} bind:value={latitude} />
<InputValue {id} input={configuration.zoom} bind:value={zoom} />
<InputValue {id} input={configuration.markers} bind:value={markers} />
<div class="relative h-full w-full">
<div
on:pointerdown|stopPropagation={selectComponent}
bind:this={mapElement}
class={twMerge(`w-full h-full`, css?.map?.class ?? '')}
style={css?.map?.style ?? ''}
/>
{#if $mode !== 'preview'}
<div
class="absolute bottom-0 left-0 px-1 py-0.5 bg-indigo-500 text-white text-2xs"
on:pointerdown={handleSyncRegion}
>
Set region
</div>
{/if}
</div>
<style global lang="postcss">
.ol-overlaycontainer-stopevent {
@apply flex flex-col justify-start items-end;
}
.ol-control button {
@apply w-7 h-7 center-center bg-white border border-gray-300 text-gray-700
rounded mt-1 mr-1 shadow duration-200 hover:bg-gray-100 focus:bg-gray-100
hover:border-gray-500 focus:border-gray-500;
}
</style>

View File

@@ -14,18 +14,13 @@
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import { getContext } from 'svelte'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
ChartJS.register(
Title,
@@ -65,21 +60,17 @@
}
]
}
$: css = concatCustomCss($app.css?.piechartcomponent, customCss)
</script>
<InputValue {id} input={configuration.theme} bind:value={theme} />
<InputValue {id} input={configuration.doughnutStyle} bind:value={doughnut} />
<RunnableWrapper flexWrap autoRefresh {componentInput} {id} bind:initializing bind:result>
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
{#if doughnut}
<Doughnut {data} {options} />
{:else}
<Pie {data} {options} />
{/if}
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
{#if doughnut}
<Doughnut {data} {options} />
{:else}
<Pie {data} {options} />
{/if}
</div>
{/if}
</RunnableWrapper>

View File

@@ -17,21 +17,16 @@
import Scatter from 'svelte-chartjs/Scatter.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type { ChartOptions, ChartData } from 'chart.js'
import { concatCustomCss } from '../../utils'
import { getContext } from 'svelte'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
let zoomable = false
let pannable = false
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
ChartJS.register(
Title,
@@ -71,17 +66,13 @@
$: data = {
datasets: result ?? []
} as ChartData<'scatter', (number | Point)[], unknown>
$: css = concatCustomCss($app.css?.scatterchartcomponent, customCss)
</script>
<InputValue {id} input={configuration.zoomable} bind:value={zoomable} />
<InputValue {id} input={configuration.pannable} bind:value={pannable} />
<RunnableWrapper flexWrap autoRefresh {componentInput} {id} bind:initializing bind:result>
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
<Scatter {data} {options} />
{/if}
</div>
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
<Scatter {data} {options} />
{/if}
</RunnableWrapper>

View File

@@ -64,7 +64,7 @@
<InputValue {id} input={configuration.style} bind:value={style} />
<InputValue {id} input={configuration.copyButton} bind:value={copyButton} />
<RunnableWrapper flexWrap {componentInput} {id} bind:initializing bind:result>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
{#if !result || result === ''}
<div class="text-gray-400 bg-gray-100 flex justify-center items-center h-full w-full">

View File

@@ -20,18 +20,13 @@
import { Scatter } from 'svelte-chartjs'
import InputValue from '../helpers/InputValue.svelte'
import type { ChartOptions, ChartData } from 'chart.js'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { getContext } from 'svelte'
import { concatCustomCss } from '../../utils'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
let logarithmicScale = false
let zoomable = false
@@ -85,18 +80,14 @@
$: data = {
datasets: result ?? []
} as ChartData<'scatter', (number | Point)[], unknown>
$: css = concatCustomCss($app.css?.timeseriescomponent, customCss)
</script>
<InputValue {id} input={configuration.logarithmicScale} bind:value={logarithmicScale} />
<InputValue {id} input={configuration.zoomable} bind:value={zoomable} />
<InputValue {id} input={configuration.pannable} bind:value={pannable} />
<RunnableWrapper flexWrap autoRefresh {componentInput} {id} bind:initializing bind:result>
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
<Scatter {data} {options} />
{/if}
</div>
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
<Scatter {data} {options} />
{/if}
</RunnableWrapper>

View File

@@ -1,11 +1,12 @@
<script lang="ts">
import { Loader2 } from 'lucide-svelte'
import { onMount } from 'svelte'
import type { AppInput } from '../../inputType'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
// export let configuration: Record<string, AppInput>
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export const staticOutputs: string[] = ['result', 'loading']
@@ -40,7 +41,12 @@
</script>
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
<RunnableWrapper flexWrap {componentInput} {id} bind:initializing bind:result>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if !Plotly}
<div class="p-2">
<Loader2 class="animate-spin" />
</div>
{/if}
<div on:pointerdown bind:this={divEl} />
</RunnableWrapper>
</div>

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { Loader2 } from 'lucide-svelte'
import { onMount } from 'svelte'
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
@@ -52,7 +53,12 @@
<InputValue {id} input={configuration.canvas} bind:value={canvas} />
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
<RunnableWrapper flexWrap {componentInput} {id} bind:initializing bind:result>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if !vegaEmbed}
<div class="p-2">
<Loader2 class="animate-spin" />
</div>
{/if}
<div on:pointerdown bind:this={divEl} />
</RunnableWrapper>
</div>

View File

@@ -1,14 +1,12 @@
export { default as AppTable } from './table/AppTable.svelte'
export { default as AppAggridTable } from './table/AppAggridTable.svelte'
export { default as AppBarChart } from './AppBarChart.svelte'
export { default as AppDisplayComponent } from './AppDisplayComponent.svelte'
export { default as AppHtml } from './AppHtml.svelte'
export { default as AppIcon } from './AppIcon.svelte'
export { default as AppImage } from './AppImage.svelte'
export { default as AppMap } from './AppMap.svelte'
export { default as AppPieChart } from './AppPieChart.svelte'
export { default as AppScatterChart } from './AppScatterChart.svelte'
export { default as AppText } from './AppText.svelte'
export { default as AppTimeseries } from './AppTimeseries.svelte'
export { default as PlotlyHtml } from './PlotlyHtml.svelte'
export { default as VegaLiteHtml } from './VegaLiteHtml.svelte'
export { default as VegaLiteHtml } from './VegaLiteHtml.svelte'

View File

@@ -1,118 +0,0 @@
<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
let pagination: boolean | undefined = undefined
let pageSize: number | undefined = 10
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} />
<InputValue {id} input={configuration.pagination} bind:value={pagination} />
<InputValue {id} input={configuration.pageSize} bind:value={pageSize} />
<RunnableWrapper flexWrap {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"
>
{#key pagination}
<AgGridSvelte
bind:rowData={result}
{columnDefs}
{pagination}
paginationPageSize={pageSize}
defaultColDef={{ flex: 1, editable: allEditable, onCellValueChanged }}
/>
{/key}
</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

@@ -1,7 +1,7 @@
<script lang="ts">
import { getContext, onMount } from 'svelte'
import type { Output } from '../../../rx'
import type { AppEditorContext, BaseAppComponent, ComponentCustomCSS } from '../../../types'
import type { AppEditorContext, BaseAppComponent } from '../../../types'
import InputValue from '../../helpers/InputValue.svelte'
import type { AppInput } from '../../../inputType'
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
@@ -14,17 +14,12 @@
import { tableOptions } from './tableOptions'
import Alert from '$lib/components/common/alert/Alert.svelte'
import type { ButtonComponent } from '../../../editor/component'
import { concatCustomCss } from '../../../utils'
import { twMerge } from 'tailwind-merge'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let actionButtons: (BaseAppComponent & ButtonComponent)[]
export let initializing: boolean | undefined = undefined
export let customCss:
| ComponentCustomCSS<'container' | 'tableHeader' | 'tableBody' | 'tableFooter'>
| undefined = undefined
export const staticOutputs: string[] = [
'selectedRow',
@@ -56,11 +51,8 @@
let table = createSvelteTable(options)
const {
app,
worldStore,
staticOutputs: staticOutputsStore
} = getContext<AppEditorContext>('AppEditorContext')
const { worldStore, staticOutputs: staticOutputsStore } =
getContext<AppEditorContext>('AppEditorContext')
let selectedRowIndex = -1
@@ -141,22 +133,13 @@
}
$: result && rerender()
$: css = concatCustomCss($app.css?.tablecomponent, customCss)
</script>
<InputValue {id} input={configuration.search} bind:value={search} />
<RunnableWrapper flexWrap {componentInput} {id} bind:initializing bind:result>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if Array.isArray(result) && result.every(isObject)}
<div
class={twMerge(
'border border-gray-300 shadow-sm divide-y divide-gray-300 h-full',
css?.container?.class ?? '',
'flex flex-col'
)}
style={css?.container?.style ?? ''}
>
<div class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full">
{#if search !== 'Disabled'}
<div class="px-2 py-1">
<div class="flex items-center">
@@ -169,14 +152,7 @@
<div class="overflow-x-auto flex-1 w-full">
<table class="relative w-full border-b border-b-gray-200">
<thead
class={twMerge(
'bg-gray-50 text-left',
css?.tableHeader?.class ?? '',
'sticky top-0 z-40'
)}
style={css?.tableHeader?.style ?? ''}
>
<thead class="sticky top-0 z-40 bg-gray-50 text-left">
{#each $table.getHeaderGroups() as headerGroup}
<tr class="divide-x">
{#each headerGroup.headers as header}
@@ -202,10 +178,7 @@
</tr>
{/each}
</thead>
<tbody
class={twMerge('divide-y divide-gray-200 bg-white', css?.tableBody?.class ?? '')}
style={css?.tableBody?.style ?? ''}
>
<tbody class="divide-y divide-gray-200 bg-white ">
{#each $table.getRowModel().rows as row, rowIndex (row.id)}
<tr
class={classNames(
@@ -262,13 +235,7 @@
</table>
</div>
<AppTableFooter
paginationEnabled={pagination}
{result}
{table}
class={css?.tableFooter.class}
style={css?.tableFooter.style}
/>
<AppTableFooter paginationEnabled={pagination} {result} {table} />
</div>
{:else if result != undefined}
<Alert title="Parsing issues" type="error" size="xs">

View File

@@ -4,7 +4,6 @@
import type { Table } from '@tanstack/svelte-table'
import { ChevronLeft, ChevronRight } from 'lucide-svelte'
import type { Readable } from 'svelte/store'
import { twMerge } from 'tailwind-merge'
import { tableOptions } from './tableOptions'
type T = Record<string, any>
@@ -12,9 +11,6 @@
export let result: Array<T>
export let paginationEnabled: boolean = false
export let table: Readable<Table<T>>
let c = ''
export { c as class }
export let style = ''
function downloadResultAsJSON() {
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(result))
@@ -27,10 +23,7 @@
}
</script>
<div
class={twMerge('px-2 py-1 text-xs gap-2 items-center justify-between', c, 'flex flex-row')}
{style}
>
<div class="px-2 py-1 text-xs flex flex-row gap-2 items-center justify-between">
{#if paginationEnabled && result.length > (tableOptions.initialState?.pagination?.pageSize ?? 25)}
<div class="flex items-center gap-2 flex-row">
<Button

View File

@@ -1,44 +1,41 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge'
import { classNames } from '$lib/utils'
import type { HorizontalAlignment, VerticalAlignment } from '../../types'
export let horizontalAlignment: HorizontalAlignment | undefined = undefined
export let verticalAlignment: VerticalAlignment | undefined = undefined
export let noWFull = false
let c = ''
export { c as class }
export let style = ''
function tailwindHorizontalAlignment(alignment?: HorizontalAlignment) {
if (!alignment) return ''
if(!alignment) return '';
const classes: Record<HorizontalAlignment, string> = {
left: 'justify-start',
center: 'justify-center',
right: 'justify-end'
right: 'justify-end',
}
return classes[alignment]
}
function tailwindVerticalAlignment(alignment?: VerticalAlignment) {
if (!alignment) return ''
if(!alignment) return '';
const classes: Record<VerticalAlignment, string> = {
top: 'items-start',
center: 'items-center',
bottom: 'items-end'
bottom: 'items-end',
}
return classes[alignment]
}
$: classes = twMerge(
$: classes = classNames(
'flex z-auto',
noWFull ? '' : 'w-full',
tailwindHorizontalAlignment(horizontalAlignment),
tailwindVerticalAlignment(verticalAlignment),
verticalAlignment ? 'h-full' : '',
c
$$props.class || ''
)
</script>
<div class={classes} {style}>
<div class={classes}>
<slot />
</div>

View File

@@ -1,10 +1,5 @@
<script lang="ts">
import type {
ConnectedAppInput,
RowAppInput,
StaticAppInput,
UserAppInput
} from '../../inputType'
import type { ConnectedAppInput, RowAppInput, StaticAppInput, UserAppInput } from '../../inputType'
import type { InlineScript } from '../../types'
import RunnableComponent from './RunnableComponent.svelte'
@@ -20,7 +15,7 @@
<RunnableComponent
{id}
{fields}
bind:fields
bind:result
runnable={{
name,

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import { isCodeInjection } from '$lib/components/flows/utils'
import { deepEqual } from 'fast-equals'
import { getContext } from 'svelte'
import type { AppInput, EvalAppInput, UploadAppInput } from '../../inputType'
import type { AppEditorContext } from '../../types'
@@ -11,34 +10,29 @@
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 = ''
let lastInput = input ? JSON.parse(JSON.stringify(input)) : undefined
$: if (input && !deepEqual(input, lastInput)) {
lastInput = JSON.parse(JSON.stringify(input))
}
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
$: state = $worldStore?.state
$: lastInput && $worldStore && handleConnection()
$: lastInput && lastInput.type == 'template' && $state && (value = getValue(lastInput))
$: lastInput && lastInput.type == 'eval' && $state && (value = evalExpr(lastInput))
$: input && $worldStore && row && handleConnection()
$: input && input.type == 'template' && $state && (value = getValue(input))
$: input && input.type == 'eval' && $state && (value = evalExpr(input))
function handleConnection() {
// console.log('handle connection', id, lastInput)
if (lastInput.type === 'connected') {
$worldStore?.connect<any>(lastInput, onValueChange)
} else if (lastInput.type === 'static' || lastInput.type == 'template') {
value = getValue(lastInput)
} else if (lastInput.type == 'eval') {
value = evalExpr(lastInput as EvalAppInput)
} else if (lastInput.type == 'upload') {
value = (lastInput as UploadAppInput).value
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') {
setTimeout(() => ((value = evalExpr(input as EvalAppInput)), 0))
} else if (input.type == 'upload') {
setTimeout(() => ((value = (input as UploadAppInput).value), 0))
} else {
value = undefined
setTimeout(() => (value = undefined), 0)
}
}
@@ -63,6 +57,7 @@
Object.fromEntries(Object.entries(value ?? {}).map((x) => [x[0], x[1].peak()]))
]
})
.concat(row ? [['row', row]] : [])
)
}
@@ -108,8 +103,8 @@
}
function onValueChange(newValue: any): void {
if (lastInput.type === 'connected' && newValue !== undefined && newValue !== null) {
const { connection } = lastInput
if (input.type === 'connected' && newValue !== undefined && newValue !== null) {
const { connection } = input
if (!connection) {
// No connection

View File

@@ -7,6 +7,7 @@
import { AppService, type CompletedJob } from '$lib/gen'
import { defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
import { getContext, onMount } from 'svelte'
import { computeFields } from '../../editor/inlineScriptsPanel/utils'
import type { AppInputs, Runnable } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
@@ -21,12 +22,11 @@
export let autoRefresh: boolean = true
export let result: any = undefined
export let forceSchemaDisplay: boolean = false
export let defaultUserInput = false
export let flexWrap = false
export let wrapperClass = ''
export let wrapperStyle = ''
export let initializing: boolean | undefined = undefined
export let gotoUrl: string | undefined = undefined
export let gotoNewTab: boolean | undefined = undefined
const {
worldStore,
@@ -37,8 +37,7 @@
jobs,
noBackend,
errorByComponent,
mode,
stateId
mode
} = getContext<AppEditorContext>('AppEditorContext')
onMount(() => {
@@ -105,9 +104,29 @@
$: outputs?.loading?.set(testIsLoading)
$: schemaStripped = stripSchema(fields, $stateId)
$: runnable?.type === 'runnableByName' && loadSchemaAndInputsByName()
function stripSchema(inputs: AppInputs, s: any): Schema {
async function loadSchemaAndInputsByName() {
if (runnable?.type === 'runnableByName') {
const { inlineScript } = runnable
// Inline scripts directly provide the schema
if (inlineScript) {
const newSchema = inlineScript.schema
const newFields = computeFields(newSchema, defaultUserInput, fields)
if (JSON.stringify(newFields) !== JSON.stringify(fields)) {
setTimeout(() => {
fields = newFields
}, 0)
}
}
}
}
$: schemaStripped = runnable && stripSchema(fields)
function stripSchema(inputs: AppInputs): Schema {
let schema =
runnable?.type == 'runnableByName' ? runnable.inlineScript?.schema : runnable?.schema
try {
@@ -220,7 +239,12 @@
{#each Object.entries(fields ?? {}) as [key, v]}
{#if v.type != 'static' && v.type != 'user'}
<InputValue {id} input={fields[key]} bind:value={runnableInputValues[key]} />
<InputValue
{id}
input={fields[key]}
bind:value={runnableInputValues[key]}
row={extraQueryParams['row'] ?? {}}
/>
{/if}
{/each}
@@ -242,13 +266,7 @@
delete $errorByComponent[previousJobId]
$errorByComponent = $errorByComponent
}
if (gotoUrl && gotoUrl != '' && result?.error == undefined) {
if (gotoNewTab) {
window.open(gotoUrl, '_blank')
} else {
goto(gotoUrl)
}
}
gotoUrl && gotoUrl != '' && result?.error == undefined && goto(gotoUrl)
}
}
}}
@@ -257,7 +275,12 @@
bind:this={testJobLoader}
/>
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}" style={wrapperStyle}>
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}">
{#if !initializing && autoRefresh === true}
<div class="flex absolute top-1 right-1">
<RefreshButton componentId={id} />
</div>
{/if}
{#if schemaStripped && Object.keys(schemaStripped?.properties ?? {}).length > 0 && (autoRefresh || forceSchemaDisplay)}
<div class="px-2 h-fit min-h-0">
<SchemaForm
@@ -293,9 +316,4 @@
<slot />
</div>
{/if}
{#if !initializing && autoRefresh === true}
<div class="flex absolute top-1 right-1 z-50">
<RefreshButton componentId={id} />
</div>
{/if}
</div>

View File

@@ -15,11 +15,10 @@
export let autoRefresh: boolean = true
export let runnableComponent: RunnableComponent | undefined = undefined
export let forceSchemaDisplay: boolean = false
export let defaultUserInput = false
export let flexWrap = false
export let runnableClass = ''
export let runnableStyle = ''
export let goto: string | undefined = undefined
export let gotoNewTab: boolean | undefined = undefined
const { staticExporter, noBackend } = getContext<AppEditorContext>('AppEditorContext')
@@ -44,10 +43,10 @@
{:else if componentInput.type === 'runnable' && isRunnableDefined()}
<RunnableComponent
gotoUrl={goto}
{gotoNewTab}
{flexWrap}
{defaultUserInput}
bind:this={runnableComponent}
fields={componentInput.fields}
bind:fields={componentInput.fields}
bind:result
runnable={componentInput.runnable}
{autoRefresh}
@@ -56,7 +55,6 @@
{forceSchemaDisplay}
{initializing}
wrapperClass={runnableClass}
wrapperStyle={runnableStyle}
>
<slot />
</RunnableComponent>

View File

@@ -3,8 +3,7 @@
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -12,9 +11,8 @@
export let configuration: Record<string, AppInput>
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'text'> | undefined = undefined
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
export const staticOutputs: string[] = ['result']
@@ -29,8 +27,6 @@
}
$: defaultValue != undefined && outputs?.result.set(defaultValue)
$: css = concatCustomCss($app.css?.checkboxcomponent, customCss)
</script>
<InputValue {id} input={configuration.label} bind:value={labelValue} />
@@ -44,8 +40,6 @@
}}
checked={defaultValue}
options={{ right: labelValue }}
textClass={css?.text?.class ?? ''}
textStyle={css?.text?.style ?? ''}
on:change={(e) => {
outputs.result.set(e.detail)
}}

View File

@@ -1,10 +1,8 @@
<script lang="ts">
import { getContext } from 'svelte'
import { twMerge } from 'tailwind-merge'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -14,9 +12,8 @@
export let inputType: 'date' | 'time' | 'datetime-local'
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let input: HTMLInputElement
let labelValue: string = 'Title'
let minValue: string = ''
@@ -32,8 +29,6 @@
}
$: input && handleInput()
$: css = concatCustomCss($app.css?.dateinputcomponent, customCss)
</script>
<InputValue {id} input={configuration.label} bind:value={labelValue} />
@@ -51,7 +46,6 @@
min={minValue}
max={maxValue}
placeholder="Type..."
class={twMerge('mx-0.5', css?.input?.class ?? '')}
style={css?.input?.style ?? ''}
class="h-full"
/>
</AlignWrapper>

View File

@@ -1,19 +1,16 @@
<script lang="ts">
import { getContext } from 'svelte'
import { twMerge } from 'tailwind-merge'
import { FileInput } from '../../../common'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: Record<string, AppInput>
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let acceptedFileTypes: string[] | undefined = undefined
let allowMultiple: boolean | undefined = undefined
@@ -27,8 +24,6 @@
async function handleChange(files: string[] | undefined) {
outputs?.result.set(files)
}
$: css = concatCustomCss($app.css?.fileinputcomponent, customCss)
</script>
<InputValue {id} input={configuration.acceptedFileTypes} bind:value={acceptedFileTypes} />
@@ -39,12 +34,11 @@
<FileInput
accept={acceptedFileTypes?.length ? acceptedFileTypes?.join(', ') : undefined}
multiple={allowMultiple}
convertTo="base64"
convertToBase64
on:change={({ detail }) => {
handleChange(detail)
}}
class={twMerge('w-full h-full', css?.container?.class)}
style={css?.container?.style}
class="w-full h-full"
>
{text}
</FileInput>

View File

@@ -1,97 +0,0 @@
<script lang="ts">
import { getContext } from 'svelte'
import Select from 'svelte-select'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../../../../defaults'
import { stopPropagation } from 'ol/events/Event'
export const staticOutputs: string[] = ['result']
export let id: string
export let configuration: Record<string, AppInput>
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { app, worldStore, connectingInput, selectedComponent } =
getContext<AppEditorContext>('AppEditorContext')
let items: { label: string; value: string }[]
let placeholder: string = 'Select an item'
$: outputs = $worldStore?.outputsById[id] as {
result: Output<string[] | undefined>
}
// $: outputs && handleOutputs()
// function handleOutputs() {
// value = outputs.result.peak()
// }
let value: { value: string }[] | undefined = outputs?.result.peak()
$: labels && handleItems()
let labels: string[] | undefined = []
function handleItems() {
if (labels) {
items = labels?.map((label) => {
return {
label,
value: label
}
})
}
}
$: value && outputs?.result.set(value.map((v) => v.value))
$: css = concatCustomCss($app.css?.selectcomponent, customCss)
</script>
<InputValue {id} input={configuration.items} bind:value={labels} />
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
<div class="app-select w-full mx-0.5" style="height: 34px" on:pointerdown|stopPropagation>
{#if !value || Array.isArray(value)}
<Select
multiple
on:change={(e) => e.stopPropagation()}
{items}
class={css?.input?.class ?? ''}
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles + css?.input?.style}
bind:value
{placeholder}
on:click={() => {
if (!$connectingInput.opened) {
$selectedComponent = id
}
}}
on:focus={() => {
$selectedComponent = id
}}
floatingConfig={{
strategy: 'fixed'
}}
/>
{:else}
Value {value} is not an array
{/if}
</div>
</AlignWrapper>
<style global>
.app-select .value-container {
padding: 0 !important;
}
.svelte-select-list {
z-index: 1000 !important;
}
</style>

View File

@@ -2,8 +2,7 @@
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -12,9 +11,8 @@
export let configuration: Record<string, AppInput>
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let input: HTMLInputElement
let defaultValue: number | undefined = undefined
@@ -35,8 +33,6 @@
}
$: input && handleInput()
$: css = concatCustomCss($app.css?.numberinputcomponent, customCss)
</script>
<InputValue {id} input={configuration.step} bind:value={step} />
@@ -48,8 +44,6 @@
<AlignWrapper {verticalAlignment}>
<input
class="mx-0.5 {css?.input?.class ?? ''}"
style={css?.input?.style ?? ''}
bind:this={input}
on:input={handleInput}
on:focus={(e) => {

View File

@@ -3,24 +3,20 @@
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import { concatCustomCss } from '../../utils'
import { twMerge } from 'tailwind-merge'
import { Badge } from '$lib/components/common'
export let id: string
export let configuration: Record<string, AppInput>
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'handles' | 'bar' | 'limits' | 'values'> | undefined =
undefined
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let min = 0
let max = 42
let step = 1
let slider: HTMLElement
let values: [number, number] = [0, 0]
@@ -29,17 +25,6 @@
}
$: outputs?.result.set(values)
$: css = concatCustomCss($app.css?.rangecomponent, customCss)
let lastStyle: string | undefined = undefined
$: if (css && slider && lastStyle !== css?.handles?.style) {
const handles = slider.querySelectorAll<HTMLSpanElement>('.rangeNub')
if (handles) {
lastStyle = css?.handles?.style
handles.forEach((handle) => (handle.style.cssText = css?.handles?.style ?? ''))
}
}
</script>
<InputValue {id} input={configuration.step} bind:value={step} />
@@ -51,43 +36,20 @@
<AlignWrapper {verticalAlignment}>
<div class="flex flex-col w-full">
<div class="flex items-center w-full gap-1 px-1">
<span class={css?.limits?.class ?? ''} style={css?.limits?.style ?? ''}>
{+min}
</span>
<span>{min}</span>
<div class="grow" on:pointerdown|stopPropagation>
<RangeSlider
bind:slider
bind:values
{step}
min={!min ? 0 : +min}
max={!max ? 1 : +max}
range
/>
<!-- <RangeSlider {step} range min={min ?? 0} max={max ?? 1} bind:values /> -->
<RangeSlider {step} range min={min ?? 0} max={max ?? 1} bind:values />
<!-- <DoubleRange bind:start bind:end /> -->
</div>
<span class={css?.limits?.class ?? ''} style={css?.limits?.style ?? ''}>
{+max}
</span>
<span>{max}</span>
</div>
<div class="flex justify-between px-1">
<span
class={twMerge(
'text-center text-sm font-medium bg-blue-100 text-blue-800 rounded px-2.5 py-0.5',
css?.values?.class ?? ''
)}
style={css?.values?.style ?? ''}
>
{values[0]}
</span>
<span
class={twMerge(
'text-center text-sm font-medium bg-blue-100 text-blue-800 rounded px-2.5 py-0.5',
css?.values?.class ?? ''
)}
style={css?.values?.style ?? ''}
>
{values[1]}
</span>
<div>
<Badge color="blue">{values[0]}</Badge>
</div>
<div>
<Badge color="blue">{values[1]}</Badge>
</div>
</div>
</div>
</AlignWrapper>

View File

@@ -3,33 +3,31 @@
import Select from 'svelte-select'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../../../../defaults'
export const staticOutputs: string[] = ['result']
export let id: string
export let configuration: Record<string, AppInput>
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { app, worldStore, connectingInput, selectedComponent } =
const { worldStore, connectingInput, selectedComponent } =
getContext<AppEditorContext>('AppEditorContext')
let items: { label: string; value: any; created?: boolean }[]
let items: { label: string; value: any }[]
let multiple: boolean = false
let placeholder: string = 'Select an item'
$: outputs = $worldStore?.outputsById[id] as {
result: Output<any | undefined>
result: Output<string | undefined>
}
let value: string | undefined = outputs?.result.peak()
let value: string | undefined = undefined
$: items && handleItems()
let listItems: { label: string; value: string; created?: boolean }[] = []
let listItems: { label: string; value: string }[] = []
function handleItems() {
listItems = Array.isArray(items)
@@ -40,73 +38,35 @@
}
})
: []
if (defaultValue) {
value = JSON.stringify(defaultValue)
if (items?.[0]?.['value'] != value) {
value = JSON.stringify(items?.[0]?.['value'])
outputs?.result.set(value)
}
}
function onChange(e: CustomEvent) {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
if (create) {
listItems = listItems.map((i) => {
delete i.created
return i
})
}
let result: any = undefined
try {
result = JSON.parse(e.detail?.['value'])
} catch (_) {}
outputs?.result.set(result)
}
$: css = concatCustomCss($app.css?.selectcomponent, customCss)
let defaultValue: any = undefined
function handleFilter(e) {
if (create) {
if (e.detail.length === 0 && filterText.length > 0) {
const prev = listItems.filter((i) => !i.created)
listItems = [
...prev,
{ value: JSON.stringify(filterText), label: filterText, created: true }
]
}
}
}
$: defaultValue && handleDefault()
function handleDefault() {
if (defaultValue) {
value = JSON.stringify(defaultValue)
outputs?.result.set(defaultValue)
}
}
let create = false
let filterText = ''
</script>
<InputValue {id} input={configuration.items} bind:value={items} />
<InputValue {id} input={configuration.multiple} bind:value={multiple} />
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
<InputValue {id} input={configuration.defaultValue} bind:value={defaultValue} />
<InputValue {id} input={configuration.create} bind:value={create} />
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
<div class="app-select w-full mx-0.5" style="height: 34px" on:pointerdown|stopPropagation>
<div class="app-select w-full" style="height: 34px" on:pointerdown|stopPropagation>
<Select
bind:filterText
on:filter={handleFilter}
--height="34px"
{multiple}
on:clear={onChange}
on:change={onChange}
items={listItems}
class={css?.input?.class ?? ''}
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles + css?.input?.style}
{value}
{placeholder}
on:click={() => {
@@ -114,21 +74,7 @@
$selectedComponent = id
}
}}
on:focus={() => {
$selectedComponent = id
}}
floatingConfig={{
strategy: 'fixed'
}}
>
<div slot="item" let:item>
{#if create}
{item.created ? 'Add new: ' : ''}
{/if}
{item.label}
</div>
</Select>
/>
</div>
</AlignWrapper>
@@ -136,7 +82,4 @@
.app-select .value-container {
padding: 0 !important;
}
.svelte-select-list {
z-index: 1000 !important;
}
</style>

View File

@@ -1,35 +1,28 @@
<script lang="ts">
import { Badge } from '$lib/components/common'
import RangeSlider from 'svelte-range-slider-pips'
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import { twMerge } from 'tailwind-merge'
import { concatCustomCss } from '../../utils'
export let id: string
export let configuration: Record<string, AppInput>
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'handle' | 'limits' | 'value'> | undefined = undefined
const { app, worldStore, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let values: [number] = [0]
let min = 0
let max = 42
let step = 1
let slider: HTMLElement
$: outputs = $worldStore?.outputsById[id] as {
result: Output<number | null>
}
let values: [number] = [outputs?.result.peak() ?? 0]
$: values && handleValues()
function handleValues() {
$: if (values) {
// Disallow 'e' character in numbers
// if(value && value.toString().includes('e')) {
// value = +value.toString().replaceAll('e', '')
@@ -37,17 +30,6 @@
const num = isNaN(+values[0]) ? null : +values[0]
outputs?.result.set(num)
}
$: css = concatCustomCss($app.css?.slidercomponent, customCss)
let lastStyle: string | undefined = undefined
$: if (css && slider && lastStyle !== css?.handle?.style) {
const handle = slider.querySelector<HTMLSpanElement>('.rangeNub')
if (handle) {
lastStyle = css?.handle?.style
handle.style.cssText = css?.handle?.style ?? ''
}
}
</script>
<InputValue {id} input={configuration.step} bind:value={step} />
@@ -57,25 +39,11 @@
<AlignWrapper {verticalAlignment}>
<div class="flex items-center w-full gap-1 px-1">
<span class={css?.limits?.class ?? ''} style={css?.limits?.style ?? ''}>
{+min}
</span>
<div class="grow" on:pointerdown|stopPropagation={() => ($selectedComponent = id)}>
<RangeSlider bind:slider bind:values {step} min={+min} max={+max} />
<span>{min}</span>
<div class="grow" on:pointerdown|stopPropagation>
<RangeSlider {step} min={min ?? 0} max={max ?? 1} bind:values />
</div>
<span class={css?.limits?.class ?? ''} style={css?.limits?.style ?? ''}>
{+max}
</span>
<span class="mx-2">
<span
class={twMerge(
'text-center text-sm font-medium bg-blue-100 text-blue-800 rounded px-2.5 py-0.5',
css?.value?.class ?? ''
)}
style={css?.value?.style ?? ''}
>
{values[0]}
</span>
</span>
<span>{max}</span>
<span class="mx-2"><Badge large color="blue">{values[0]}</Badge></span>
</div>
</AlignWrapper>

View File

@@ -1,10 +1,8 @@
<script lang="ts">
import { getContext } from 'svelte'
import { twMerge } from 'tailwind-merge'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -14,10 +12,8 @@
export let inputType = 'text'
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
export let appCssKey: 'textinputcomponent' | 'passwordinputcomponent' = 'textinputcomponent'
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let input: HTMLInputElement
let placeholder: string | undefined = undefined
@@ -32,8 +28,6 @@
}
$: input && handleInput()
$: css = concatCustomCss($app.css?.[appCssKey], customCss)
</script>
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
@@ -42,8 +36,7 @@
<AlignWrapper {verticalAlignment}>
<input
class={twMerge('mx-0.5', css?.input?.class ?? '')}
style={css?.input?.style ?? ''}
class="mx-0.5"
on:focus={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))

View File

@@ -2,8 +2,7 @@
import { getContext } from 'svelte'
import type { AppInput } from '../../../inputType'
import type { Output } from '../../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../../types'
import { concatCustomCss } from '../../../utils'
import type { AppEditorContext } from '../../../types'
import AlignWrapper from '../../helpers/AlignWrapper.svelte'
import InputValue from '../../helpers/InputValue.svelte'
import CurrencyInput from './CurrencyInput.svelte'
@@ -12,9 +11,8 @@
export let configuration: Record<string, AppInput>
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
let defaultValue: number | undefined = undefined
@@ -39,8 +37,6 @@
$: value != undefined && handleInput()
$: defaultValue != undefined && handleDefault()
$: css = concatCustomCss($app.css?.currencycomponent, customCss)
</script>
<InputValue {id} input={configuration.defaultValue} bind:value={defaultValue} />
@@ -53,12 +49,7 @@
{#key locale}
{#key currency}
<CurrencyInput
inputClasses={{
formatted: 'p-0 ' + css?.input?.class,
wrapper: 'w-full',
formattedZero: 'text-black ' + css?.input?.class
}}
style={css?.input?.style}
inputClasses={{ formatted: 'p-0', wrapper: 'w-full', formattedZero: 'text-black' }}
bind:value
{currency}
{locale}

View File

@@ -35,7 +35,6 @@
export let isNegativeAllowed: boolean = true
export let fractionDigits: number = DEFAULT_FRACTION_DIGITS
export let inputClasses: InputClasses | null = null
export let style: string = ''
// Formats value as: e.g. $1,523.00 | -$1,523.00
const formatCurrency = (
@@ -176,7 +175,6 @@
? inputClasses?.formattedNegative ?? DEFAULT_CLASS_FORMATTED_NEGATIVE
: ''}
"
{style}
type="text"
inputmode="numeric"
name={`formatted-${name}`}

View File

@@ -6,4 +6,4 @@ export { default as AppNumberInput } from './AppNumberInput.svelte'
export { default as AppRangeInput } from './AppRangeInput.svelte'
export { default as AppSelect } from './AppSelect.svelte'
export { default as AppSliderInputs } from './AppSliderInputs.svelte'
export { default as AppTextInput } from './AppTextInput.svelte'
export { default as AppTextInput } from './AppTextInput.svelte'

View File

@@ -2,20 +2,20 @@
import { getContext } from 'svelte'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS, GridItem } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext, GridItem } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: Record<string, AppInput>
export let componentContainerHeight: number
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
let noPadding: boolean | undefined = undefined
export const staticOutputs: string[] = []
const { app, focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
let gridContent: string[] | undefined = undefined
function onFocus() {
$focusedGrid = {
parentComponentId: id,
@@ -24,24 +24,18 @@
}
$: $selectedComponent === id && onFocus()
$: css = concatCustomCss($app.css?.containercomponent, customCss)
</script>
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
<div class="border">
{#if $app.subgrids?.[`${id}-0`]}
<SubGridEditor
{noPadding}
{id}
class={css?.container.class}
style={css?.container.style}
bind:subGrid={$app.subgrids[`${id}-0`]}
containerHeight={componentContainerHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/if}
</div>
{#if $app.subgrids?.[`${id}-0`]}
<SubGridEditor
{noPadding}
bind:subGrid={$app.subgrids[`${id}-0`]}
containerHeight={componentContainerHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/if}

View File

@@ -1,14 +1,6 @@
<script lang="ts">
import { getContext } from 'svelte'
import { twMerge } from 'tailwind-merge'
import type { AppInput } from '../../inputType'
import type {
AppEditorContext,
ComponentCustomCSS,
HorizontalAlignment,
VerticalAlignment
} from '../../types'
import { concatCustomCss } from '../../utils'
import type { HorizontalAlignment, VerticalAlignment } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -16,34 +8,17 @@
export let configuration: Record<string, AppInput>
export let horizontalAlignment: HorizontalAlignment | undefined = undefined
export let verticalAlignment: VerticalAlignment | undefined = undefined
export let customCss: ComponentCustomCSS<'container' | 'divider'> | undefined = undefined
export let position: 'horizontal' | 'vertical'
const { app } = getContext<AppEditorContext>('AppEditorContext')
let size = 2
let color = '#00000060'
$: css = concatCustomCss($app.css?.[position + 'dividercomponent'], customCss)
</script>
<InputValue {id} input={configuration.size} bind:value={size} />
<InputValue {id} input={configuration.color} bind:value={color} />
<AlignWrapper
{horizontalAlignment}
{verticalAlignment}
class={twMerge(css?.container?.class, 'h-full')}
style={css?.container?.style}
>
<AlignWrapper {horizontalAlignment} {verticalAlignment} class="h-full">
<div
class={twMerge(
`rounded-full ${position === 'horizontal' ? 'w-full' : 'h-full'}`,
css?.divider?.class ?? ''
)}
style="
{position === 'horizontal' ? 'height' : 'width'}: {size}px;
background-color: {color};
{css?.divider?.style ?? ''}
"
class="rounded-full {position === 'horizontal' ? 'w-full' : 'h-full'}"
style="{position === 'horizontal' ? 'height' : 'width'}: {size}px; background-color: {color}"
/>
</AlignWrapper>

View File

@@ -1,95 +0,0 @@
<script lang="ts">
import { getContext } from 'svelte'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
import Portal from 'svelte-portal'
import { concatCustomCss } from '../../utils'
import { Button, ButtonType, Drawer, DrawerContent } from '$lib/components/common'
import { twMerge } from 'tailwind-merge'
import { AlignWrapper } from '../helpers'
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export let id: string
export let configuration: Record<string, AppInput>
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let noWFull = false
const { app, focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
let gridContent: string[] | undefined = undefined
let noPadding: boolean | undefined = undefined
let drawerTitle: string | undefined = undefined
let appDrawer: Drawer
let labelValue: string
let color: ButtonType.Color
let size: ButtonType.Size
let disabled: boolean | undefined = undefined
let fillContainer: boolean | undefined = undefined
$: css = concatCustomCss($app.css?.containercomponent, customCss)
</script>
<div class="h-full w-full">
<AlignWrapper {noWFull} {horizontalAlignment} {verticalAlignment}>
<Button
btnClasses={twMerge(
$app.css?.['buttoncomponent']?.['button']?.class,
fillContainer ? 'w-full h-full' : ''
)}
{disabled}
on:pointerdown={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
}}
on:click={async (e) => {
$focusedGrid = {
parentComponentId: id,
subGridIndex: 0
}
appDrawer.toggleDrawer()
}}
{size}
{color}
>
<div>{labelValue}</div>
</Button>
</AlignWrapper>
</div>
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<InputValue {id} input={configuration.drawerTitle} bind:value={drawerTitle} />
<InputValue {id} input={configuration.label} bind:value={labelValue} />
<InputValue {id} input={configuration.color} bind:value={color} />
<InputValue {id} input={configuration.size} bind:value={size} />
<InputValue {id} input={configuration.fillContainer} bind:value={fillContainer} />
<Portal target="#app-editor-top-level-drawer">
<Drawer bind:this={appDrawer} size="800px" alwaysOpen positionClass="!absolute">
<DrawerContent
title={drawerTitle}
on:close={() => {
appDrawer?.toggleDrawer()
$focusedGrid = undefined
}}
>
{#if $app.subgrids?.[`${id}-0`]}
<SubGridEditor
{noPadding}
{id}
class={css?.container.class}
style={css?.container.style}
bind:subGrid={$app.subgrids[`${id}-0`]}
containerHeight={1200}
on:focus={() => {
$selectedComponent = id
}}
/>
{/if}
</DrawerContent>
</Drawer>
</Portal>

View File

@@ -1,73 +0,0 @@
<script lang="ts">
import { getContext } from 'svelte'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import InputValue from '../helpers/InputValue.svelte'
import { Pane, Splitpanes } from 'svelte-splitpanes'
import { deepEqual } from 'fast-equals'
export let id: string
export let configuration: Record<string, AppInput>
export let componentContainerHeight: number
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export let horizontal: boolean = false
export let panes: number[]
export const staticOutputs: string[] = []
const { app, focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
let noPadding: boolean | undefined = undefined
function onFocus() {
$focusedGrid = {
parentComponentId: id,
subGridIndex: 0
}
}
$: $selectedComponent === id && onFocus()
$: css = concatCustomCss($app.css?.containercomponent, customCss)
let sumedup = [50, 50]
$: {
let ns = panes.map((x) => (x / panes.reduce((a, b) => a + b, 0)) * 100)
if (!deepEqual(ns, sumedup)) {
sumedup = ns
}
}
</script>
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<div class="h-full w-full border" on:pointerdown|stopPropagation>
<Splitpanes {horizontal}>
{#each sumedup as paneSize, index (index)}
<Pane size={paneSize} minSize={20}>
{#if $app.subgrids?.[`${id}-${index}`]}
<SubGridEditor
noYPadding
{noPadding}
{id}
shouldHighlight={$focusedGrid?.subGridIndex === index}
class={css?.container.class}
style={css?.container.style}
bind:subGrid={$app.subgrids[`${id}-${index}`]}
containerHeight={horizontal
? (componentContainerHeight * paneSize) / 100 - 1
: componentContainerHeight - 8}
on:focus={() => {
$selectedComponent = id
$focusedGrid = {
parentComponentId: id,
subGridIndex: index
}
}}
/>
{/if}
</Pane>
{/each}
</Splitpanes>
</div>

View File

@@ -4,17 +4,14 @@
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import type { AppEditorContext, GridItem } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: Record<string, AppInput>
export let subGrids: GridItem[][] | undefined = undefined
export let componentContainerHeight: number
export let tabs: string[]
export let customCss:
| ComponentCustomCSS<'tabRow' | 'tabs' | 'selectedTab' | 'container'>
| undefined = undefined
export const staticOutputs: string[] = ['selectedTabIndex']
const { app, worldStore, focusedGrid, selectedComponent } =
@@ -33,19 +30,8 @@
selectedTabIndex: Output<number | null>
}
$: outputs?.selectedTabIndex && handleOutputs()
function handleTabSelection() {
outputs?.selectedTabIndex.set(selectedIndex)
if ($selectedComponent != id) {
$selectedComponent = id
}
if ($focusedGrid?.parentComponentId != id || $focusedGrid?.subGridIndex != selectedIndex) {
$focusedGrid = {
parentComponentId: id,
subGridIndex: selectedIndex
}
}
}
$: selectedIndex >= 0 && handleTabSelection()
@@ -60,46 +46,29 @@
}
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
$: css = concatCustomCss($app.css?.tabscomponent, customCss)
function handleOutputs() {
outputs?.selectedTabIndex.set(outputs.selectedTabIndex.peak())
}
</script>
<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 class={css?.tabRow?.class} style={css?.tabRow?.style}>
<div bind:clientHeight={tabHeight}>
<Tabs bind:selected>
{#each tabs ?? [] as res}
<Tab
value={res}
class={css?.tabs?.class}
style={css?.tabs?.style}
selectedClass={css?.selectedTab?.class}
selectedStyle={css?.selectedTab?.style}
>
<Tab value={res}>
<span class="font-semibold">{res}</span>
</Tab>
{/each}
</Tabs>
</div>
{#if $app.subgrids}
{#each tabs ?? [] as res, i}
<SubGridEditor
{id}
visible={i === selectedIndex}
bind:subGrid={$app.subgrids[`${id}-${i}`]}
{noPadding}
class={css?.container?.class}
style={css?.container?.style}
containerHeight={componentContainerHeight - tabHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/each}
{#if $app.subgrids?.[`${id}-${selectedIndex}`]}
<SubGridEditor
bind:subGrid={$app.subgrids[`${id}-${selectedIndex}`]}
{noPadding}
containerHeight={componentContainerHeight - tabHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/if}
</div>

View File

@@ -1,5 +1,3 @@
export { default as AppContainer } from './AppContainer.svelte'
export { default as AppDivider } from './AppDivider.svelte'
export { default as AppDrawer } from './AppDrawer.svelte'
export { default as AppSplitpanes } from './AppSplitpanes.svelte'
export { default as AppTabs } from './AppTabs.svelte'
export { default as AppTabs } from './AppTabs.svelte'

View File

@@ -24,7 +24,7 @@
import Icon from 'svelte-awesome'
import { faCode, faPlus, faSliders } from '@fortawesome/free-solid-svg-icons'
import ContextPanel from './contextPanel/ContextPanel.svelte'
import { classNames, encodeState } from '$lib/utils'
import { encodeState } from '$lib/utils'
import AppPreview from './AppPreview.svelte'
import { userStore, workspaceStore } from '$lib/stores'
@@ -36,6 +36,7 @@
import UnsavedConfirmationModal from '$lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte'
import { page } from '$app/stores'
import CssSettings from './componentsPanel/CssSettings.svelte'
import { findGridItem } from './appUtils'
export let app: App
export let path: string
@@ -59,12 +60,14 @@
const runnableComponents = writable<Record<string, () => Promise<void>>>({})
const errorByComponent = writable<Record<string, { error: string; componentId: string }>>({})
const focusedGrid = writable<FocusedGrid | undefined>(undefined)
setContext<AppEditorContext>('AppEditorContext', {
worldStore,
staticOutputs,
app: appStore,
lazyGrid: writable([]),
summary: summaryStore,
selectedComponent,
mode,
@@ -80,9 +83,7 @@
noBackend: false,
errorByComponent,
openDebugRun: writable(undefined),
focusedGrid,
stateId: writable(0),
parentWidth: writable(0)
focusedGrid
})
let timeout: NodeJS.Timeout | undefined = undefined
@@ -126,7 +127,7 @@
{#if $connectingInput.opened}
<div
class="absolute w-full h-screen bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
class="absolute w-full h-screen bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
/>
{/if}
{#if !$userStore?.operator}
@@ -138,7 +139,7 @@
{#if previewing}
<SplitPanesWrapper>
<div
class={twMerge('h-full w-full', $appStore.css?.['app']?.['viewer']?.class)}
class={twMerge('bg-gray-100 h-full w-full', $appStore.css?.['app']?.['viewer']?.class)}
style={$appStore.css?.['app']?.['viewer']?.style}
>
<AppPreview
@@ -165,10 +166,6 @@
<Splitpanes horizontal>
<Pane size={$connectingInput?.opened ? 100 : 70}>
<div
on:pointerdown={(e) => {
$selectedComponent = undefined
$focusedGrid = undefined
}}
class={twMerge(
'bg-gray-100 h-full w-full',
$appStore.css?.['app']?.['viewer']?.class
@@ -176,17 +173,14 @@
style={$appStore.css?.['app']?.['viewer']?.style}
>
<div
class={classNames(
'relative mx-auto w-full h-full overflow-auto',
app.fullscreen ? '' : 'max-w-6xl'
)}
class="relative mx-auto w-full h-full overflow-auto {app.fullscreen
? ''
: 'max-w-6xl'}"
>
{#if $appStore.grid}
<div on:pointerdown|stopPropagation class={width}>
<div class={width}>
<GridEditor {policy} />
</div>
<div id="app-editor-top-level-drawer" />
{/if}
</div>
</div>

View File

@@ -51,7 +51,7 @@
UserAppInput
} from '../inputType'
import type { AppEditorContext } from '../types'
import { allItems, toStatic } from '../utils'
import { toStatic } from '../utils'
import AppExportButton from './AppExportButton.svelte'
import AppInputs from './AppInputs.svelte'
import type { AppComponent } from './component/components'
@@ -124,7 +124,7 @@
}
async function computeTriggerables() {
const allTriggers = await Promise.all(
allItems($app.grid, $app.subgrids)
$app.grid
.flatMap((x) => {
let c = x.data as AppComponent
let r: (AppInput | undefined)[] = [c.componentInput]
@@ -293,7 +293,7 @@
</PanelSection>
</Pane>
<Pane size={75}>
<div class="h-full w-full overflow-auto">
<div class="h-full w-full overflow-hidden">
{#if selectedJobId}
{#if !job}
<Skeleton layout={[[40]]} />

View File

@@ -6,7 +6,7 @@
import AppComponentInput from './AppComponentInput.svelte'
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
const { app } = getContext<AppEditorContext>('AppEditorContext')
const { app, lazyGrid } = getContext<AppEditorContext>('AppEditorContext')
let resourceOnly: boolean = true
</script>
@@ -18,9 +18,9 @@
<Toggle bind:checked={resourceOnly} options={{ right: 'Resource only' }} />
</div>
<div class="gap-4 flex flex-col pt-4">
{#each $app.grid as gridItem (gridItem.data.id)}
{#each $lazyGrid as gridItem (gridItem.data.id)}
<div>
{#if gridItem?.data?.type === 'tablecomponent'}
{#if gridItem.data.type === 'tablecomponent'}
<div>
<AppComponentInput bind:component={gridItem.data} {resourceOnly} />
<div class="ml-4 mt-4">

Some files were not shown because too many files have changed in this diff Show More