Compare commits
63 Commits
rf/flatten
...
v1.71.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c96e2351d9 | ||
|
|
ddb4916a2e | ||
|
|
1bb5ed9ae0 | ||
|
|
b5b32f00b3 | ||
|
|
c06311faf8 | ||
|
|
8a639b6e7d | ||
|
|
05f568fb8c | ||
|
|
e515c70e71 | ||
|
|
6adc875610 | ||
|
|
8a0d1158c4 | ||
|
|
ea2ebfa92e | ||
|
|
ba856be10d | ||
|
|
333b873ee9 | ||
|
|
2785b05064 | ||
|
|
a67f10eeb6 | ||
|
|
287b2db22f | ||
|
|
a4e4d188ad | ||
|
|
2244e83b9d | ||
|
|
42d1cd6456 | ||
|
|
4b64e75bd1 | ||
|
|
51a7eaaeb0 | ||
|
|
8589b70ccf | ||
|
|
0bf6f23c9e | ||
|
|
e56869092a | ||
|
|
6b8758f4a5 | ||
|
|
fbc929ba1b | ||
|
|
97602ac6db | ||
|
|
8ee9d67f4f | ||
|
|
4bf6e753f1 | ||
|
|
70eab303bd | ||
|
|
c051ffeb42 | ||
|
|
ebb68e5320 | ||
|
|
04a076f1db | ||
|
|
ebd2e0323e | ||
|
|
cd25570003 | ||
|
|
e95f8ef6bf | ||
|
|
c3d1c8ac39 | ||
|
|
d38aff2fe2 | ||
|
|
95851ea486 | ||
|
|
b690d801d4 | ||
|
|
104e4ac5e7 | ||
|
|
e87f4fc44b | ||
|
|
e1f686d850 | ||
|
|
7da7dac3ac | ||
|
|
c2e5afd4e0 | ||
|
|
ad9c386f41 | ||
|
|
a4e3f98b7d | ||
|
|
dd28308c3c | ||
|
|
833c2655ea | ||
|
|
a8295d0b5a | ||
|
|
897e2f6b53 | ||
|
|
5bb77edf45 | ||
|
|
8ddcf4d9c1 | ||
|
|
33ebe2da8e | ||
|
|
b3ee747014 | ||
|
|
fa105b4cae | ||
|
|
483407cdf0 | ||
|
|
008c30fcaa | ||
|
|
3387bb0d83 | ||
|
|
e08e7e4ae6 | ||
|
|
ea1b2c29b9 | ||
|
|
4ad6fbefd3 | ||
|
|
397ecd64d4 |
4
.github/workflows/docker-image.yml
vendored
4
.github/workflows/docker-image.yml
vendored
@@ -182,7 +182,7 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push privately
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
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@v3
|
||||
uses: docker/build-push-action@v4
|
||||
if: github.event_name != 'pull_request'
|
||||
with:
|
||||
context: .
|
||||
|
||||
2
.github/workflows/pypi_on_release.yml
vendored
2
.github/workflows/pypi_on_release.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
||||
password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
- name: Build and push publicly
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: "{{defaultContext}}:lsp"
|
||||
push: true
|
||||
|
||||
4
.github/workflows/uffizzi-build.yml
vendored
4
.github/workflows/uffizzi-build.yml
vendored
@@ -25,12 +25,12 @@ jobs:
|
||||
run: echo "UUID_TAG_APP=$(uuidgen)" >> $GITHUB_ENV
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
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@v2
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
push: true
|
||||
context: ./
|
||||
|
||||
86
CHANGELOG.md
86
CHANGELOG.md
@@ -1,6 +1,92 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
184
backend/Cargo.lock
generated
184
backend/Cargo.lock
generated
@@ -255,9 +255,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.6.7"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fb79c228270dcf2426e74864cabc94babb5dbab01a4314e702d2f16540e1591"
|
||||
checksum = "6137c6234afb339e75e764c866e3594900f0211e1315d33779f269bbe2ec6967"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
@@ -324,9 +324,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.5.3"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "better_scoped_tls"
|
||||
@@ -525,9 +525,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.6"
|
||||
version = "4.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
|
||||
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
@@ -540,9 +540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.1.0"
|
||||
version = "4.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
||||
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@@ -553,9 +553,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
||||
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
@@ -581,9 +581,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
|
||||
checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
|
||||
|
||||
[[package]]
|
||||
name = "const_format"
|
||||
@@ -619,7 +619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time 0.3.19",
|
||||
"time 0.3.20",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@@ -704,9 +704,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.14"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
@@ -966,9 +966,9 @@ checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60"
|
||||
checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-iter"
|
||||
@@ -987,9 +987,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.0"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
|
||||
checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
@@ -1324,9 +1324,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
|
||||
checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -1678,9 +1678,9 @@ checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.25"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -2048,15 +2048,6 @@ 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"
|
||||
@@ -2149,18 +2140,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.10"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e0072973714303aa6e3631c7e8e777970cf4bdd25dc4932e41031027b8bcc4e"
|
||||
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.10"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0629cbd6b897944899b1f10496d9c4a7ac5878d45fd61bc22e9e79bfbbc29597"
|
||||
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
@@ -2516,9 +2507,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
|
||||
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"toml_edit",
|
||||
@@ -2798,15 +2789,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.14"
|
||||
@@ -3003,7 +2985,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython#f2515405b59f8fe3b9be59d4454783c2dc2d83d1"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-compiler-core",
|
||||
@@ -3012,7 +2994,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython#f2515405b59f8fe3b9be59d4454783c2dc2d83d1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -3029,7 +3011,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython#c4b67896662b16b5699a779c0e52aa0ca2587fec"
|
||||
source = "git+https://github.com/RustPython/RustPython#f2515405b59f8fe3b9be59d4454783c2dc2d83d1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -3083,9 +3065,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.11"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
|
||||
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dyn-clone",
|
||||
@@ -3097,9 +3079,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.11"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
|
||||
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3697,9 +3679,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "swc_atoms"
|
||||
version = "0.4.37"
|
||||
version = "0.4.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f88175a66f5a7c189e752bda520e148317776ecb22c75adc2c2f24c490834bd0"
|
||||
checksum = "5a172f2e444ae1378286cd27ff2a5cb26eadfd7a77c98ccb0edde8992857be1e"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
@@ -3711,9 +3693,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_common"
|
||||
version = "0.29.32"
|
||||
version = "0.29.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc8e0e8109b26be70c82d9709562fc88cbcc09e03c2458221cf216c0088dea2"
|
||||
checksum = "a8a75c46065858a37cdda2c1c6fd056986e3b7752d5ec332e91ce312c6a22749"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ast_node",
|
||||
@@ -3738,9 +3720,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_ast"
|
||||
version = "0.96.7"
|
||||
version = "0.98.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "621c66e27fbb6cbb6434a4e2b25e439e9a2583cc3419a4a83eba51d16ac0cd7b"
|
||||
checksum = "7b1f6bc913d0f1daf0fa713a64660aed27848e0047ee671ab2206ad602730d1f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"is-macro",
|
||||
@@ -3755,9 +3737,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_parser"
|
||||
version = "0.124.12"
|
||||
version = "0.127.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b3f472b3dfbfd279de364d2b014459a281824b938e243a8739037c445d6b6c"
|
||||
checksum = "3875db58a1515382c670679062133294e5ec88aff08776f5fb6e4f3c09c0f5f9"
|
||||
dependencies = [
|
||||
"either",
|
||||
"enum_kind",
|
||||
@@ -3823,9 +3805,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.108"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3840,16 +3822,15 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
"rustix",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3926,9 +3907,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.19"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53250a3b3fed8ff8fd988587d8925d26a83ac3845d9e03b220b37f34c2b8d6c2"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
@@ -3944,9 +3925,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a460aeb8de6dcb0f381e1ee05f1cd56fcf5a5f6eb8187ff3d8f0b11078d38b7c"
|
||||
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
@@ -4090,19 +4071,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.5.1"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
|
||||
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.18.1"
|
||||
version = "0.19.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
|
||||
checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4153,9 +4134,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.3.5"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858"
|
||||
checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
@@ -4475,9 +4456,11 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "029df4cc8238cefc911704ff8fa210853a0f3bce2694d8f51181dd41ee0f3301"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/youknowone/unicode_names2.git?tag=v0.6.0+character-alias#4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde"
|
||||
dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
@@ -4766,7 +4749,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -4793,7 +4776,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -4826,7 +4809,7 @@ dependencies = [
|
||||
"sql-builder",
|
||||
"sqlx",
|
||||
"tempfile",
|
||||
"time 0.3.19",
|
||||
"time 0.3.20",
|
||||
"tokio",
|
||||
"tokio-tar",
|
||||
"tokio-util",
|
||||
@@ -4848,7 +4831,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"chrono",
|
||||
@@ -4863,7 +4846,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
@@ -4876,7 +4859,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -4901,7 +4884,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4909,7 +4892,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
@@ -4923,7 +4906,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
@@ -4935,7 +4918,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
@@ -4950,7 +4933,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deno_core",
|
||||
@@ -4964,7 +4947,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -4987,7 +4970,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -5101,6 +5084,15 @@ 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"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -19,7 +19,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.69.0"
|
||||
version = "1.71.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,16 @@
|
||||
-- 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';
|
||||
@@ -60,6 +60,60 @@ 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",
|
||||
"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(([0, 0, 0, 0], port));
|
||||
|
||||
@@ -72,60 +126,6 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
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(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.69.0
|
||||
version: 1.71.0
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
|
||||
@@ -1311,7 +1311,9 @@ 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": "new_user"}))
|
||||
.json(
|
||||
&serde_json::json!({"email" : &nu.email, "name": &nu.name, "event": "global_add"}),
|
||||
)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| tracing::error!("Error sending new user webhook: {}", e.to_string()));
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
use std::str::FromStr;
|
||||
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::BASE_URL;
|
||||
use crate::{
|
||||
apps::AppWithLastVersion,
|
||||
@@ -20,7 +20,7 @@ use crate::{
|
||||
utils::require_super_admin,
|
||||
HTTP_CLIENT,
|
||||
};
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
use axum::response::Redirect;
|
||||
use axum::{
|
||||
body::StreamBody,
|
||||
@@ -30,7 +30,7 @@ use axum::{
|
||||
routing::{delete, get, post},
|
||||
Json, Router,
|
||||
};
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
use stripe::CustomerId;
|
||||
use windmill_audit::{audit_log, ActionKind};
|
||||
use windmill_common::{
|
||||
@@ -63,12 +63,13 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/tarball", get(tarball_workspace))
|
||||
.route("/premium_info", get(premium_info));
|
||||
|
||||
#[cfg(enterprise)]
|
||||
let router = {
|
||||
router
|
||||
.route("/checkout", get(stripe_checkout))
|
||||
.route("/billing_portal", get(stripe_portal));
|
||||
};
|
||||
#[cfg(feature = "enterprise")]
|
||||
tracing::info!("stripe enabled");
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
let router = router
|
||||
.route("/checkout", get(stripe_checkout))
|
||||
.route("/billing_portal", get(stripe_portal));
|
||||
|
||||
router
|
||||
}
|
||||
@@ -230,13 +231,13 @@ async fn premium_info(
|
||||
Ok(Json(row))
|
||||
}
|
||||
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
#[derive(Deserialize)]
|
||||
struct PlanQuery {
|
||||
plan: String,
|
||||
}
|
||||
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
async fn stripe_checkout(
|
||||
authed: Authed,
|
||||
Path(w_id): Path<String>,
|
||||
@@ -302,7 +303,7 @@ async fn stripe_checkout(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(enterprise)]
|
||||
#[cfg(feature = "enterprise")]
|
||||
async fn stripe_portal(
|
||||
authed: Authed,
|
||||
Path(w_id): Path<String>,
|
||||
@@ -964,7 +965,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": "new_invite"}))
|
||||
.json(&serde_json::json!({"email" : &nu.email, "event": "workspace_invite"}))
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| tracing::error!("Error sending new user webhook: {}", e.to_string()));
|
||||
@@ -1001,6 +1002,15 @@ 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),
|
||||
|
||||
@@ -351,7 +351,10 @@ pub async fn push<'c>(
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_super_admin {
|
||||
if usage > MAX_FREE_EXECS {
|
||||
if usage > MAX_FREE_EXECS
|
||||
&& !matches!(job_payload, JobPayload::Dependencies { .. })
|
||||
&& !matches!(job_payload, JobPayload::FlowDependencies { .. })
|
||||
{
|
||||
return Err(error::Error::BadRequest(format!(
|
||||
"User {email} has exceeded the free usage limit of {MAX_FREE_EXECS} that applies outside of premium workspaces."
|
||||
)));
|
||||
@@ -466,10 +469,10 @@ pub async fn push<'c>(
|
||||
}
|
||||
JobPayload::Flow(flow) => {
|
||||
let value_json = sqlx::query_scalar!(
|
||||
"SELECT value FROM flow WHERE path = $1 AND workspace_id = $2",
|
||||
flow,
|
||||
workspace_id
|
||||
)
|
||||
"SELECT value FROM flow WHERE path = $1 AND workspace_id = $2",
|
||||
flow,
|
||||
workspace_id
|
||||
)
|
||||
.fetch_optional(&mut tx)
|
||||
.await?
|
||||
.ok_or_else(|| Error::InternalErr(format!("not found flow at path {:?}", flow)))?;
|
||||
|
||||
@@ -383,7 +383,7 @@ lazy_static::lazy_static! {
|
||||
.unwrap();
|
||||
static ref WORKER_UPTIME_OPTS: prometheus::Opts = prometheus::opts!(
|
||||
"worker_uptime",
|
||||
"Total number of milliseconds since the worker has started"
|
||||
"Total number of seconds since the worker has started"
|
||||
);
|
||||
|
||||
static ref TIMEOUT: u16 = std::env::var("TIMEOUT")
|
||||
@@ -445,15 +445,11 @@ pub async fn run_worker(
|
||||
|
||||
insert_initial_ping(worker_instance, &worker_name, ip, db).await;
|
||||
|
||||
let uptime_metric = prometheus::register_int_counter!(WORKER_UPTIME_OPTS
|
||||
let uptime_metric = prometheus::register_counter!(WORKER_UPTIME_OPTS
|
||||
.clone()
|
||||
.const_label("name", &worker_name))
|
||||
.unwrap();
|
||||
uptime_metric.inc_by(
|
||||
((Instant::now() - start_time).as_millis() - uptime_metric.get() as u128)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
|
||||
let worker_execution_duration = prometheus::register_histogram_vec!(
|
||||
prometheus::HistogramOpts::new(
|
||||
@@ -465,6 +461,14 @@ pub async fn run_worker(
|
||||
)
|
||||
.expect("register prometheus metric");
|
||||
|
||||
let worker_execution_duration_counter = prometheus::register_counter!(prometheus::opts!(
|
||||
"worker_execution_duration_counter",
|
||||
"Total number of seconds spent executing jobs"
|
||||
)
|
||||
.const_label("name", &worker_name))
|
||||
.expect("register prometheus metric");
|
||||
|
||||
|
||||
let worker_sleep_duration = prometheus::register_histogram!(prometheus::HistogramOpts::new(
|
||||
"worker_sleep_duration",
|
||||
"Duration sleeping waiting for job",
|
||||
@@ -472,6 +476,15 @@ pub async fn run_worker(
|
||||
.const_label("name", &worker_name),)
|
||||
.expect("register prometheus metric");
|
||||
|
||||
|
||||
let worker_sleep_duration_counter = prometheus::register_counter!(prometheus::opts!(
|
||||
"worker_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",
|
||||
@@ -479,6 +492,13 @@ pub async fn run_worker(
|
||||
.const_label("name", &worker_name),)
|
||||
.expect("register prometheus metric");
|
||||
|
||||
let worker_pull_duration_counter = prometheus::register_counter!(prometheus::opts!(
|
||||
"worker_pull_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),
|
||||
@@ -526,11 +546,12 @@ pub async fn run_worker(
|
||||
worker_busy.set(0);
|
||||
|
||||
uptime_metric.inc_by(
|
||||
((Instant::now() - start_time).as_millis() - uptime_metric.get() as u128)
|
||||
(((Instant::now() - start_time).as_millis() as f64)/1000.0 - uptime_metric.get())
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
|
||||
let do_break = async {
|
||||
if last_ping.elapsed().as_secs() > NUM_SECS_ENV_CHECK {
|
||||
sqlx::query!(
|
||||
@@ -574,7 +595,8 @@ pub async fn run_worker(
|
||||
(job, timer) = {
|
||||
let timer = worker_pull_duration.start_timer();
|
||||
pull(&db, WHITELIST_WORKSPACES.clone(), BLACKLIST_WORKSPACES.clone()).map(|x| (x, timer)) } => {
|
||||
drop(timer);
|
||||
let duration_pull_s = timer.stop_and_record();
|
||||
worker_pull_duration_counter.inc_by(duration_pull_s);
|
||||
(false, job)
|
||||
},
|
||||
}
|
||||
@@ -680,6 +702,8 @@ pub async fn run_worker(
|
||||
.await;
|
||||
};
|
||||
|
||||
let duration = _timer.stop_and_record();
|
||||
worker_execution_duration_counter.inc_by(duration);
|
||||
|
||||
if !*KEEP_JOB_DIR && !(is_flow && same_worker) {
|
||||
let _ = tokio::fs::remove_dir_all(job_dir).await;
|
||||
@@ -689,9 +713,9 @@ pub async fn run_worker(
|
||||
|
||||
let _timer = worker_sleep_duration
|
||||
.start_timer();
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(*SLEEP_QUEUE)).await;
|
||||
|
||||
let duration = _timer.stop_and_record();
|
||||
worker_sleep_duration_counter.inc_by(duration);
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!(worker = %worker_name, "run_worker: pulling jobs: {}", err);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// windmill
|
||||
export { setClient } from "https://deno.land/x/windmill@v1.66.0/mod.ts";
|
||||
export * from "https://deno.land/x/windmill@v1.66.0/windmill-api/index.ts";
|
||||
export { setClient } from "https://deno.land/x/windmill@v1.69.3/mod.ts";
|
||||
export * from "https://deno.land/x/windmill@v1.69.3/windmill-api/index.ts";
|
||||
|
||||
// cliffy
|
||||
export { Command } from "https://deno.land/x/cliffy@v0.25.7/command/command.ts";
|
||||
@@ -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";
|
||||
|
||||
@@ -51,9 +51,11 @@ export async function browserLogin(
|
||||
const url = `${baseUrl}user/cli?port=${port}`
|
||||
console.log(`Login by going to ${url}`);
|
||||
try {
|
||||
open(url)
|
||||
await open(url)
|
||||
console.log("Opened browser for you");
|
||||
} catch { }
|
||||
} catch {
|
||||
console.error(`Failed to open browser, please navigate to ${url}`)
|
||||
}
|
||||
const firstConnection = await server.accept();
|
||||
const httpFirstConnection = Deno.serveHttp(firstConnection);
|
||||
const firstRequest = (await httpFirstConnection.nextRequest())!;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Command, DenoLandProvider, UpgradeCommand } from "./deps.ts";
|
||||
import { Command, CompletionsCommand, 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.69.0";
|
||||
const VERSION = "v1.71.0";
|
||||
|
||||
let command: any = new Command()
|
||||
.name("wmill")
|
||||
@@ -60,7 +60,8 @@ let command: any = new Command()
|
||||
],
|
||||
provider: new DenoLandProvider({ name: "wmill" }),
|
||||
}),
|
||||
);
|
||||
)
|
||||
.command("completions", new CompletionsCommand());
|
||||
|
||||
if (Number.parseInt(VERSION.replace("v", "").replace(".", "")) > 1700) {
|
||||
command = command
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"lock": "",
|
||||
"path": null,
|
||||
"type": "rawscript",
|
||||
"content": "// import * as wmill from \"https://deno.land/x/windmill@v1.50.0/mod.ts\"\n\nexport async function main(x: string) {\n console.log(\"Hello from Deno! The argument x is \" + x);\n return x;\n}\n",
|
||||
"content": "// import * as wmill from \"https://deno.land/x/windmill@v1.69.3/mod.ts\"\n\nexport async function main(x: string) {\n console.log(\"Hello from Deno! The argument x is \" + x);\n return x;\n}\n",
|
||||
"language": "deno",
|
||||
"input_transforms": {
|
||||
"x": {
|
||||
|
||||
@@ -312,8 +312,9 @@ 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>")
|
||||
.arguments("<workspace_name:string:workspace>")
|
||||
.action(switchC as any)
|
||||
.command("add")
|
||||
.description("Add a workspace")
|
||||
|
||||
@@ -4,8 +4,9 @@ set -e
|
||||
npm ci --ignore-scripts
|
||||
npx --yes openapi-typescript-codegen --input ../backend/windmill-api/openapi.yaml \
|
||||
--output ./src --useOptions \
|
||||
&& sed -i '213 i \\ request.referrerPolicy = \"no-referrer\"\n' src/core/request.ts
|
||||
npx --yes denoify
|
||||
&& sed -i '213 i \\ request.referrerPolicy = \"no-referrer\"\n' src/core/request.ts
|
||||
npx --yes denoify
|
||||
rm -rf windmill-api
|
||||
mv deno_dist windmill-api
|
||||
sed -i 's/buffer DENOIFY: UNKNOWN NODE BUILTIN/node:buffer/' ./windmill-api/core/request.ts
|
||||
rm -rf src/
|
||||
|
||||
205
frontend/package-lock.json
generated
205
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill",
|
||||
"version": "1.69.0",
|
||||
"version": "1.71.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill",
|
||||
"version": "1.69.0",
|
||||
"version": "1.71.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
@@ -14,11 +14,13 @@
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@redocly/json-to-json-schema": "^0.0.1",
|
||||
"@tanstack/svelte-table": "^8.7.6",
|
||||
"ag-grid-svelte": "^0.1.4",
|
||||
"async-mutex": "^0.4.0",
|
||||
"chart.js": "^3.9.1",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-plugin-zoom": "^2.0.0",
|
||||
"date-fns": "^2.29.3",
|
||||
"fast-equals": "^4.0.3",
|
||||
"highlight.js": "^11.7.0",
|
||||
"lucide-svelte": "^0.115.0",
|
||||
"monaco-editor": "0.33.0",
|
||||
@@ -28,12 +30,12 @@
|
||||
"svelte-autosize": "^1.0.1",
|
||||
"svelte-chartjs": "^3.1.0",
|
||||
"svelte-portal": "^2.2.0",
|
||||
"svelte-select": "^5.0.2",
|
||||
"svelte-select": "^5.3.1",
|
||||
"tailwind-merge": "^1.9.1",
|
||||
"vscode-ws-jsonrpc": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.29.2",
|
||||
"@playwright/test": "^1.31.1",
|
||||
"@sveltejs/adapter-static": "^1.0.0",
|
||||
"@sveltejs/kit": "^1.0.0-next.589",
|
||||
"@sveltejs/package": "^1.0.2",
|
||||
@@ -43,7 +45,7 @@
|
||||
"@types/vscode": "~1.74.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@windmill-labs/svelte-grid": "^5.1.3",
|
||||
"@windmill-labs/svelte-grid": "^5.1.4",
|
||||
"@windmill-labs/svelvet": "^4.0.20",
|
||||
"@zerodevx/svelte-toast": "^0.8.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
@@ -602,16 +604,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.0.5.tgz",
|
||||
"integrity": "sha512-iDdOsaCHZH/0FM0yNBYt+cJxJF9S5jrYWNtDZOiDFMiZ7uxMJ/71h8eTwoVifEAruv9p9rlMPYCGIgMjOz95FQ=="
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.1.tgz",
|
||||
"integrity": "sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg=="
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.1.0.tgz",
|
||||
"integrity": "sha512-TSogMPVxbRe77QCj1dt8NmRiJasPvuc+eT5jnJ6YpLqgOD2zXc5UA3S1qwybN+GVCDNdKfpKy1oj8RpzLJvh6A==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.1.tgz",
|
||||
"integrity": "sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.0.5"
|
||||
"@floating-ui/core": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||
@@ -752,19 +754,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.2.tgz",
|
||||
"integrity": "sha512-+3/GPwOgcoF0xLz/opTnahel1/y42PdcgZ4hs+BZGIUjtmEFSXGg+nFoaH3NSmuc7a6GSFwXDJ5L7VXpqzigNg==",
|
||||
"version": "1.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.31.1.tgz",
|
||||
"integrity": "sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.29.2"
|
||||
"playwright-core": "1.31.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@polka/url": {
|
||||
@@ -1263,9 +1268,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@windmill-labs/svelte-grid": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.3.tgz",
|
||||
"integrity": "sha512-SzfuJ2qYkBYC73x3l+x9l7WcgU+kMlRoFkCgSCOfggi3z5zJU9eX1VYsV1wDjtQVU9OUaAciv1xlUR4OPxrFlg==",
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.4.tgz",
|
||||
"integrity": "sha512-alxQ8su/osmHodl1JMta+0dvlc2qnYwiXsoeC8Ys8hrLywD03y5tjxYV0L0WXvOnMKG1S9GbqGuDVCk+UmVuKg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@windmill-labs/svelvet": {
|
||||
@@ -1357,6 +1362,23 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ag-grid-community": {
|
||||
"version": "28.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-28.2.1.tgz",
|
||||
"integrity": "sha512-DMZh/xD/FqYP17qJ1M92PolTYe+hrKuEaf+A4h13O6qn2x/xZQrTRGW5DgnQLR/uLMe1XXZQPKR3UKgAlKo69A==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/ag-grid-svelte": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ag-grid-svelte/-/ag-grid-svelte-0.1.4.tgz",
|
||||
"integrity": "sha512-yKJKZ1o3aE9dgaK4WtmjG+vA9GKqErznvFisDnzi+PPGWXDCSNWuoDGCUpEFJtHKrfooLoUZZHYHi8I9sZ+BCA==",
|
||||
"dependencies": {
|
||||
"svelte": "^3.55.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ag-grid-community": "^28"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
@@ -2439,7 +2461,8 @@
|
||||
"node_modules/dedent-js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
|
||||
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ=="
|
||||
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
@@ -2971,6 +2994,11 @@
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-equals": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz",
|
||||
"integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg=="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.2.12",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
||||
@@ -3849,6 +3877,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
@@ -4244,6 +4273,7 @@
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lower-case": "^2.0.2",
|
||||
"tslib": "^2.0.3"
|
||||
@@ -4478,6 +4508,7 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
|
||||
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"no-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
@@ -4572,9 +4603,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.2.tgz",
|
||||
"integrity": "sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==",
|
||||
"version": "1.31.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.1.tgz",
|
||||
"integrity": "sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -6182,25 +6213,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-floating-ui": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.1.6.tgz",
|
||||
"integrity": "sha512-lJfrc34+xSxKs+5AtnYj32uRIjaxGjhT92cOiNL3zEqaJ755JxUqXCf6tk+9G1wkCuqkK9A8tscVBsyY3iLmVQ==",
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.2.8.tgz",
|
||||
"integrity": "sha512-8Ifi5CD2Ui7FX7NjJRmutFtXjrB8T/FMNoS2H8P81t5LHK4I9G4NIs007rLWG/nRl7y+zJUXa3tWuTjYXw/O5A==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.4",
|
||||
"svelte2tsx": "^0.5.11"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-floating-ui/node_modules/svelte2tsx": {
|
||||
"version": "0.5.23",
|
||||
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.5.23.tgz",
|
||||
"integrity": "sha512-jYFnugTQRFmUpvLXPQrKzVYcW5ErT+0QCxg027Zx9BuvYefMZFuoBSTDYe7viPEFGrPPiLgT2m7f5n9khE7f7Q==",
|
||||
"dependencies": {
|
||||
"dedent-js": "^1.0.1",
|
||||
"pascal-case": "^3.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.24",
|
||||
"typescript": "^4.1.2"
|
||||
"@floating-ui/core": "^1.1.0",
|
||||
"@floating-ui/dom": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-highlight": {
|
||||
@@ -6324,12 +6342,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/svelte-select": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.0.2.tgz",
|
||||
"integrity": "sha512-SsyIwcRVl38041xk7HoPCAew8D6ypTrMvoNcwOgAEWz9Yycgd/uZ58gMSubxSDtkW/ohuYmmHf5OlGCKIqn9Cw==",
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.3.1.tgz",
|
||||
"integrity": "sha512-TKlH22FEOr/KYNX4dzBJntNzeI0v0eZYU3VEo2uz/gar6xZdhQ3KT81hvD595GfSB7wiFdYc9SO42wrcgm9W4Q==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.10",
|
||||
"svelte-floating-ui": "1.1.6"
|
||||
"@floating-ui/dom": "^1.2.1",
|
||||
"svelte-floating-ui": "1.2.8"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-splitpanes": {
|
||||
@@ -6667,6 +6685,7 @@
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -7462,16 +7481,16 @@
|
||||
}
|
||||
},
|
||||
"@floating-ui/core": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.0.5.tgz",
|
||||
"integrity": "sha512-iDdOsaCHZH/0FM0yNBYt+cJxJF9S5jrYWNtDZOiDFMiZ7uxMJ/71h8eTwoVifEAruv9p9rlMPYCGIgMjOz95FQ=="
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.1.tgz",
|
||||
"integrity": "sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg=="
|
||||
},
|
||||
"@floating-ui/dom": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.1.0.tgz",
|
||||
"integrity": "sha512-TSogMPVxbRe77QCj1dt8NmRiJasPvuc+eT5jnJ6YpLqgOD2zXc5UA3S1qwybN+GVCDNdKfpKy1oj8RpzLJvh6A==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.1.tgz",
|
||||
"integrity": "sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==",
|
||||
"requires": {
|
||||
"@floating-ui/core": "^1.0.5"
|
||||
"@floating-ui/core": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
@@ -7578,13 +7597,14 @@
|
||||
}
|
||||
},
|
||||
"@playwright/test": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.2.tgz",
|
||||
"integrity": "sha512-+3/GPwOgcoF0xLz/opTnahel1/y42PdcgZ4hs+BZGIUjtmEFSXGg+nFoaH3NSmuc7a6GSFwXDJ5L7VXpqzigNg==",
|
||||
"version": "1.31.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.31.1.tgz",
|
||||
"integrity": "sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.29.2"
|
||||
"fsevents": "2.3.2",
|
||||
"playwright-core": "1.31.1"
|
||||
}
|
||||
},
|
||||
"@polka/url": {
|
||||
@@ -7904,9 +7924,9 @@
|
||||
}
|
||||
},
|
||||
"@windmill-labs/svelte-grid": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.3.tgz",
|
||||
"integrity": "sha512-SzfuJ2qYkBYC73x3l+x9l7WcgU+kMlRoFkCgSCOfggi3z5zJU9eX1VYsV1wDjtQVU9OUaAciv1xlUR4OPxrFlg==",
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.4.tgz",
|
||||
"integrity": "sha512-alxQ8su/osmHodl1JMta+0dvlc2qnYwiXsoeC8Ys8hrLywD03y5tjxYV0L0WXvOnMKG1S9GbqGuDVCk+UmVuKg==",
|
||||
"dev": true
|
||||
},
|
||||
"@windmill-labs/svelvet": {
|
||||
@@ -7980,6 +8000,20 @@
|
||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
||||
"dev": true
|
||||
},
|
||||
"ag-grid-community": {
|
||||
"version": "28.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-28.2.1.tgz",
|
||||
"integrity": "sha512-DMZh/xD/FqYP17qJ1M92PolTYe+hrKuEaf+A4h13O6qn2x/xZQrTRGW5DgnQLR/uLMe1XXZQPKR3UKgAlKo69A==",
|
||||
"peer": true
|
||||
},
|
||||
"ag-grid-svelte": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/ag-grid-svelte/-/ag-grid-svelte-0.1.4.tgz",
|
||||
"integrity": "sha512-yKJKZ1o3aE9dgaK4WtmjG+vA9GKqErznvFisDnzi+PPGWXDCSNWuoDGCUpEFJtHKrfooLoUZZHYHi8I9sZ+BCA==",
|
||||
"requires": {
|
||||
"svelte": "^3.55.0"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
@@ -8743,7 +8777,8 @@
|
||||
"dedent-js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
|
||||
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ=="
|
||||
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
|
||||
"dev": true
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
@@ -9151,6 +9186,11 @@
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-equals": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-4.0.3.tgz",
|
||||
"integrity": "sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg=="
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.12",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
||||
@@ -9826,6 +9866,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
@@ -10130,6 +10171,7 @@
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lower-case": "^2.0.2",
|
||||
"tslib": "^2.0.3"
|
||||
@@ -10301,6 +10343,7 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
|
||||
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"no-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
@@ -10374,9 +10417,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"playwright-core": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.2.tgz",
|
||||
"integrity": "sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==",
|
||||
"version": "1.31.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.1.tgz",
|
||||
"integrity": "sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
@@ -11496,23 +11539,12 @@
|
||||
}
|
||||
},
|
||||
"svelte-floating-ui": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.1.6.tgz",
|
||||
"integrity": "sha512-lJfrc34+xSxKs+5AtnYj32uRIjaxGjhT92cOiNL3zEqaJ755JxUqXCf6tk+9G1wkCuqkK9A8tscVBsyY3iLmVQ==",
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.2.8.tgz",
|
||||
"integrity": "sha512-8Ifi5CD2Ui7FX7NjJRmutFtXjrB8T/FMNoS2H8P81t5LHK4I9G4NIs007rLWG/nRl7y+zJUXa3tWuTjYXw/O5A==",
|
||||
"requires": {
|
||||
"@floating-ui/dom": "^1.0.4",
|
||||
"svelte2tsx": "^0.5.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"svelte2tsx": {
|
||||
"version": "0.5.23",
|
||||
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.5.23.tgz",
|
||||
"integrity": "sha512-jYFnugTQRFmUpvLXPQrKzVYcW5ErT+0QCxg027Zx9BuvYefMZFuoBSTDYe7viPEFGrPPiLgT2m7f5n9khE7f7Q==",
|
||||
"requires": {
|
||||
"dedent-js": "^1.0.1",
|
||||
"pascal-case": "^3.1.1"
|
||||
}
|
||||
}
|
||||
"@floating-ui/core": "^1.1.0",
|
||||
"@floating-ui/dom": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"svelte-highlight": {
|
||||
@@ -11578,12 +11610,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"svelte-select": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.0.2.tgz",
|
||||
"integrity": "sha512-SsyIwcRVl38041xk7HoPCAew8D6ypTrMvoNcwOgAEWz9Yycgd/uZ58gMSubxSDtkW/ohuYmmHf5OlGCKIqn9Cw==",
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.3.1.tgz",
|
||||
"integrity": "sha512-TKlH22FEOr/KYNX4dzBJntNzeI0v0eZYU3VEo2uz/gar6xZdhQ3KT81hvD595GfSB7wiFdYc9SO42wrcgm9W4Q==",
|
||||
"requires": {
|
||||
"@floating-ui/dom": "^1.0.10",
|
||||
"svelte-floating-ui": "1.1.6"
|
||||
"@floating-ui/dom": "^1.2.1",
|
||||
"svelte-floating-ui": "1.2.8"
|
||||
}
|
||||
},
|
||||
"svelte-splitpanes": {
|
||||
@@ -11834,7 +11866,8 @@
|
||||
"typescript": {
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg=="
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.16.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill",
|
||||
"version": "1.69.0",
|
||||
"version": "1.71.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.29.2",
|
||||
"@playwright/test": "^1.31.1",
|
||||
"@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.3",
|
||||
"@windmill-labs/svelte-grid": "^5.1.4",
|
||||
"@windmill-labs/svelvet": "^4.0.20",
|
||||
"@zerodevx/svelte-toast": "^0.8.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
@@ -66,11 +66,13 @@
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@redocly/json-to-json-schema": "^0.0.1",
|
||||
"@tanstack/svelte-table": "^8.7.6",
|
||||
"ag-grid-svelte": "^0.1.4",
|
||||
"async-mutex": "^0.4.0",
|
||||
"chart.js": "^3.9.1",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-plugin-zoom": "^2.0.0",
|
||||
"date-fns": "^2.29.3",
|
||||
"fast-equals": "^4.0.3",
|
||||
"highlight.js": "^11.7.0",
|
||||
"lucide-svelte": "^0.115.0",
|
||||
"monaco-editor": "0.33.0",
|
||||
@@ -80,7 +82,7 @@
|
||||
"svelte-autosize": "^1.0.1",
|
||||
"svelte-chartjs": "^3.1.0",
|
||||
"svelte-portal": "^2.2.0",
|
||||
"svelte-select": "^5.0.2",
|
||||
"svelte-select": "^5.3.1",
|
||||
"tailwind-merge": "^1.9.1",
|
||||
"vscode-ws-jsonrpc": "^2.0.1"
|
||||
},
|
||||
|
||||
4
frontend/src/global.d.ts
vendored
4
frontend/src/global.d.ts
vendored
@@ -44,7 +44,7 @@ declare module '@windmill-labs/svelte-grid' {
|
||||
fastStart?: boolean
|
||||
throttleUpdate?: number
|
||||
throttleResize?: number
|
||||
|
||||
onTopId?: string
|
||||
scroller?: undefined
|
||||
sensor?: number
|
||||
}
|
||||
@@ -60,7 +60,7 @@ declare module '@windmill-labs/svelte-grid' {
|
||||
mount: CustomEvent<>
|
||||
},
|
||||
Slots<T>
|
||||
> {}
|
||||
> { }
|
||||
}
|
||||
|
||||
declare module '@windmill-labs/svelte-grid/build/helper/index.mjs' {
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { json } from 'svelte-highlight/languages'
|
||||
import TableCustom from './TableCustom.svelte'
|
||||
import { truncate } from '$lib/utils'
|
||||
import { Button } from './common'
|
||||
import { copyToClipboard, truncate } from '$lib/utils'
|
||||
import { Button, Drawer, DrawerContent } from './common'
|
||||
import autosize from 'svelte-autosize'
|
||||
import { ClipboardCopy } from 'lucide-svelte'
|
||||
|
||||
export let result: any
|
||||
export let requireHtmlApproval = false
|
||||
@@ -86,16 +87,36 @@
|
||||
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 <input type="checkbox" bind:checked={forceJson} /></div
|
||||
>{/if}{#if typeof result == 'object' && Object.keys(result).length > 0}<div
|
||||
class="mb-2 text-sm text-gray-700"
|
||||
>The result keys are: <b>{truncate(Object.keys(result).join(', '), 50)}</b></div
|
||||
class="mb-2 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
|
||||
>{/if}{#if !forceJson && resultKind == 'table-col'}<div
|
||||
class="grid grid-flow-col-dense border border-gray-200 rounded-md "
|
||||
>
|
||||
@@ -223,10 +244,8 @@
|
||||
><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>
|
||||
|
||||
@@ -138,8 +138,18 @@
|
||||
|
||||
export function setCode(ncode: string): void {
|
||||
code = ncode
|
||||
if (editor) {
|
||||
editor.setValue(ncode)
|
||||
if (editor?.getModel()) {
|
||||
// editor.setValue(ncode)
|
||||
editor.pushUndoStop()
|
||||
|
||||
editor.executeEdits('set', [
|
||||
{
|
||||
range: editor.getModel()!.getFullModelRange(), // full range
|
||||
text: ncode
|
||||
}
|
||||
])
|
||||
|
||||
editor.pushUndoStop()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
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'
|
||||
@@ -145,6 +146,7 @@
|
||||
|
||||
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)
|
||||
@@ -154,7 +156,8 @@
|
||||
selectedId: selectedIdStore,
|
||||
schedule: scheduleStore,
|
||||
select,
|
||||
previewArgs: previewArgsStore
|
||||
previewArgs: previewArgsStore,
|
||||
scriptEditorDrawer
|
||||
})
|
||||
|
||||
async function loadSchedule() {
|
||||
@@ -181,6 +184,7 @@
|
||||
</script>
|
||||
|
||||
{#if !$userStore?.operator}
|
||||
<ScriptEditorDrawer bind:this={$scriptEditorDrawer} />
|
||||
<UnsavedConfirmationModal />
|
||||
|
||||
<Drawer bind:this={flowViewer} size="75%">
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
</div>
|
||||
<FlowProgressBar {job} bind:reset={jobProgressReset} />
|
||||
|
||||
<div class="overflow-y-auto grow divide-y divide-gray-600 ">
|
||||
<div class="overflow-y-auto grow divide-y divide-gray-600 pr-4">
|
||||
<div class="max-h-1/2 overflow-auto border-b border-gray-700">
|
||||
<SchemaForm
|
||||
noVariablePicker
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
localFlowModuleStates?.[innerModules?.[i - 1]?.id ?? '']?.type ==
|
||||
FlowStatusModule.type.SUCCESS
|
||||
) {
|
||||
localFlowModuleStates[mod.id ?? ''] = { type: mod.type }
|
||||
localFlowModuleStates[mod.id ?? ''] = { type: mod.type, args: job?.args }
|
||||
} else if (
|
||||
mod.type === FlowStatusModule.type.WAITING_FOR_EXECUTOR &&
|
||||
localFlowModuleStates[mod.id ?? '']?.scheduled_for == undefined
|
||||
@@ -109,7 +109,8 @@
|
||||
type: mod.type,
|
||||
scheduled_for: 'scheduled for ' + displayDate(job?.['scheduled_for'], true),
|
||||
job_id: job?.id,
|
||||
parent_module: mod['parent_module']
|
||||
parent_module: mod['parent_module'],
|
||||
args: job?.args
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -329,10 +330,12 @@
|
||||
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,
|
||||
@@ -397,10 +400,12 @@
|
||||
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,
|
||||
@@ -497,6 +502,9 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="px-1 border-b border-black">
|
||||
<JobArgs args={node.args} />
|
||||
</div>
|
||||
<FlowJobResult
|
||||
loading={job['running'] == true}
|
||||
noBorder
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
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[] = []
|
||||
@@ -59,12 +60,13 @@
|
||||
<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 ?? '')}>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
export let initialPath: string = ''
|
||||
export let template: 'pgsql' | 'mysql' | 'script' = 'script'
|
||||
export let initialArgs: Record<string, any> = {}
|
||||
export let lockedLanguage = false
|
||||
|
||||
const langs: [string, SupportedLanguage][] = [
|
||||
['Typescript', Script.language.DENO],
|
||||
@@ -214,7 +215,13 @@
|
||||
bind:value={script.summary}
|
||||
placeholder="Short summary to be displayed when listed"
|
||||
/>
|
||||
|
||||
<h2 class="border-b pb-1 mt-12 mb-6">Language</h2>
|
||||
{#if lockedLanguage}
|
||||
<div class="text-sm text-gray-600 italic mb-2">
|
||||
As a forked script, the language '{script.language}' cannot be modified.
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-row gap-2 flex-wrap">
|
||||
{#each langs as [label, lang]}
|
||||
{@const isPicked = script.language == lang && template == 'script'}
|
||||
@@ -228,6 +235,7 @@
|
||||
template = 'script'
|
||||
initContent(lang, script.kind, template)
|
||||
}}
|
||||
disabled={lockedLanguage}
|
||||
>
|
||||
<LanguageIcon {lang} /><span class="ml-2 py-4">{label}</span>
|
||||
</Button>
|
||||
@@ -237,6 +245,7 @@
|
||||
variant="border"
|
||||
color={template == 'pgsql' ? 'blue' : 'dark'}
|
||||
btnClasses={template == 'pgsql' ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
disabled={lockedLanguage}
|
||||
on:click={() => {
|
||||
script.language = Script.language.DENO
|
||||
template = 'pgsql'
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
|
||||
onMount(() => {
|
||||
inferSchema(code)
|
||||
loadPastTests()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
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
|
||||
@@ -87,6 +88,8 @@
|
||||
bind:justValue={scriptPath}
|
||||
{items}
|
||||
placeholder="Pick a {itemKind}"
|
||||
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
|
||||
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -110,6 +110,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
export function focus() {
|
||||
editor?.focus()
|
||||
}
|
||||
|
||||
let width = 0
|
||||
async function loadMonaco() {
|
||||
model = meditor.createModel(code, lang, mUri.parse(uri))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let options: {
|
||||
left?: string
|
||||
@@ -7,6 +8,8 @@
|
||||
} = {}
|
||||
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)
|
||||
@@ -22,7 +25,13 @@
|
||||
>
|
||||
{#if Boolean(options?.left)}
|
||||
<span
|
||||
class="mr-2 text-sm font-medium duration-200 {disabled ? 'text-gray-600' : 'text-gray-900'}"
|
||||
class={twMerge(
|
||||
'ml-2 font-medium duration-200',
|
||||
disabled ? 'text-gray-500' : 'text-gray-900',
|
||||
size === 'xs' ? 'text-xs' : 'text-sm',
|
||||
textClass
|
||||
)}
|
||||
style={textStyle}
|
||||
>
|
||||
{options?.left}
|
||||
</span>
|
||||
@@ -51,9 +60,13 @@
|
||||
</div>
|
||||
{#if Boolean(options?.right)}
|
||||
<span
|
||||
class="ml-2 text-sm font-medium duration-200
|
||||
{disabled ? 'text-gray-500' : 'text-gray-900'}
|
||||
{size === 'xs' ? 'text-xs' : 'text-sm'}"
|
||||
class={twMerge(
|
||||
'ml-2 font-medium duration-200',
|
||||
disabled ? 'text-gray-500' : 'text-gray-900',
|
||||
size === 'xs' ? 'text-xs' : 'text-sm',
|
||||
textClass
|
||||
)}
|
||||
style={textStyle}
|
||||
>
|
||||
{options?.right}
|
||||
</span>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -95,7 +95,6 @@
|
||||
<InputValue {id} input={configuration.triggerOnAppLoad} bind:value={triggerOnAppLoad} />
|
||||
|
||||
<InputValue
|
||||
row={extraQueryParams['row']}
|
||||
{id}
|
||||
input={configuration.disabled}
|
||||
bind:value={disabled}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import type RunnableComponent from '../helpers/RunnableComponent.svelte'
|
||||
@@ -17,10 +18,11 @@
|
||||
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 { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let labelValue: string = 'Default label'
|
||||
let color: ButtonType.Color
|
||||
@@ -47,6 +49,8 @@
|
||||
isLoading = value
|
||||
}
|
||||
})
|
||||
|
||||
$: css = concatCustomCss($app.css?.formcomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.goto} bind:value={goto} />
|
||||
@@ -64,9 +68,13 @@
|
||||
autoRefresh={false}
|
||||
forceSchemaDisplay={true}
|
||||
runnableClass="!block"
|
||||
runnableStyle={css?.container.style}
|
||||
>
|
||||
<AlignWrapper {horizontalAlignment}>
|
||||
<div class="flex flex-col gap-2 px-4 w-full">
|
||||
<div
|
||||
class="flex flex-col gap-2 px-4 w-full {css?.container?.class ?? ''}"
|
||||
style={css?.container?.style ?? ''}
|
||||
>
|
||||
<div>
|
||||
{#if noInputs}
|
||||
<div class="text-gray-600 italic text-sm my-4">
|
||||
@@ -84,7 +92,8 @@
|
||||
{#if !noInputs}
|
||||
<Button
|
||||
loading={isLoading}
|
||||
btnClasses="my-1"
|
||||
btnClasses="my-1 {css?.button?.class ?? ''}"
|
||||
style={css?.button?.style ?? ''}
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
window.dispatchEvent(new Event('pointerup'))
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } 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
|
||||
@@ -20,10 +21,11 @@
|
||||
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 { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let labelValue: string = 'Default label'
|
||||
let color: ButtonType.Color
|
||||
@@ -35,6 +37,8 @@
|
||||
let ownClick: boolean = false
|
||||
|
||||
let errors: Record<string, string> = {}
|
||||
let open: boolean = false
|
||||
|
||||
$: errorsMessage = Object.values(errors)
|
||||
.filter((x) => x != '')
|
||||
.join('\n')
|
||||
@@ -62,14 +66,13 @@
|
||||
|
||||
$: loading = isLoading && ownClick
|
||||
|
||||
let open: boolean = false
|
||||
$: css = concatCustomCss($app?.css?.formbuttoncomponent, customCss)
|
||||
</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}
|
||||
@@ -80,6 +83,8 @@
|
||||
<Modal
|
||||
{open}
|
||||
title={labelValue}
|
||||
class={css?.popup.class}
|
||||
style={css?.popup.style}
|
||||
on:canceled={() => {
|
||||
open = false
|
||||
}}
|
||||
@@ -149,6 +154,8 @@
|
||||
{disabled}
|
||||
{size}
|
||||
{color}
|
||||
btnClasses={css?.button?.class ?? ''}
|
||||
style={css?.button?.style ?? ''}
|
||||
on:click={(e) => {
|
||||
open = true
|
||||
}}
|
||||
|
||||
@@ -15,13 +15,18 @@
|
||||
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,
|
||||
@@ -77,17 +82,21 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$: 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 bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if result}
|
||||
{#if lineChart}
|
||||
<Line {data} options={lineOptions} />
|
||||
{:else}
|
||||
<Bar {data} options={barOptions} />
|
||||
<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}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
<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
|
||||
@@ -25,8 +32,8 @@
|
||||
{#key result}
|
||||
<iframe
|
||||
frameborder="0"
|
||||
style="height: {h}px; width: {w}px"
|
||||
class="p-0"
|
||||
style="height: {h}px; width: {w}px; {css?.container?.style ?? ''}"
|
||||
class="p-0 {css?.container?.class ?? ''}"
|
||||
title="sandbox"
|
||||
srcdoc={result
|
||||
? '<scr' + `ipt type="application/javascript" src="/tailwind.js"></script>` + result
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import { AlignWrapper, InputValue, RunnableWrapper } from '../helpers'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import { AlignWrapper, InputValue } from '../helpers'
|
||||
import { loadIcon } from '../icon'
|
||||
|
||||
export let id: string
|
||||
@@ -8,6 +11,9 @@
|
||||
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
|
||||
@@ -22,6 +28,8 @@
|
||||
iconComponent = await loadIcon(icon)
|
||||
}
|
||||
}
|
||||
|
||||
$: css = concatCustomCss($app.css?.iconcomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.icon} bind:value={icon} />
|
||||
@@ -29,13 +37,20 @@
|
||||
<InputValue {id} input={configuration.color} bind:value={color} />
|
||||
<InputValue {id} input={configuration.strokeWidth} bind:value={strokeWidth} />
|
||||
|
||||
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
|
||||
<AlignWrapper
|
||||
{horizontalAlignment}
|
||||
{verticalAlignment}
|
||||
class={css?.container?.class ?? ''}
|
||||
style={css?.container?.style ?? ''}
|
||||
>
|
||||
{#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>
|
||||
|
||||
@@ -1,34 +1,41 @@
|
||||
<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
|
||||
let customStyles: string | undefined = undefined
|
||||
|
||||
$: css = concatCustomCss($app.css?.imagecomponent, customCss)
|
||||
</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={customStyles}
|
||||
class="w-full h-full {fit[imageFit || 'cover']}"
|
||||
>
|
||||
style={css?.image?.style ?? ''}
|
||||
class={twMerge(`w-full h-full ${fit[imageFit || 'cover']}`, css?.image?.class ?? '')}
|
||||
/>
|
||||
|
||||
@@ -14,13 +14,18 @@
|
||||
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,
|
||||
@@ -60,17 +65,21 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$: 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 bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if result}
|
||||
{#if doughnut}
|
||||
<Doughnut {data} {options} />
|
||||
{:else}
|
||||
<Pie {data} {options} />
|
||||
<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}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -17,16 +17,21 @@
|
||||
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,
|
||||
@@ -66,13 +71,17 @@
|
||||
$: 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 bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if result}
|
||||
<Scatter {data} {options} />
|
||||
{/if}
|
||||
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
|
||||
{#if result}
|
||||
<Scatter {data} {options} />
|
||||
{/if}
|
||||
</div>
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -20,13 +20,18 @@
|
||||
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
|
||||
@@ -80,6 +85,8 @@
|
||||
$: data = {
|
||||
datasets: result ?? []
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>
|
||||
|
||||
$: css = concatCustomCss($app.css?.timeseriescomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.logarithmicScale} bind:value={logarithmicScale} />
|
||||
@@ -87,7 +94,9 @@
|
||||
<InputValue {id} input={configuration.pannable} bind:value={pannable} />
|
||||
|
||||
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if result}
|
||||
<Scatter {data} {options} />
|
||||
{/if}
|
||||
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
|
||||
{#if result}
|
||||
<Scatter {data} {options} />
|
||||
{/if}
|
||||
</div>
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<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']
|
||||
@@ -42,11 +41,6 @@
|
||||
|
||||
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
|
||||
<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>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
@@ -54,11 +53,6 @@
|
||||
|
||||
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<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 bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if Array.isArray(result) && result.every(isObject)}
|
||||
<div
|
||||
class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full"
|
||||
bind:clientHeight
|
||||
bind:clientWidth
|
||||
>
|
||||
<div
|
||||
on:pointerdown|stopPropagation={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
style:height="{clientHeight}px"
|
||||
style:width="{clientWidth}px"
|
||||
class="ag-theme-alpine"
|
||||
>
|
||||
{#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>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import type { Output } from '../../../rx'
|
||||
import type { AppEditorContext, BaseAppComponent } from '../../../types'
|
||||
import type { AppEditorContext, BaseAppComponent, ComponentCustomCSS } from '../../../types'
|
||||
import InputValue from '../../helpers/InputValue.svelte'
|
||||
import type { AppInput } from '../../../inputType'
|
||||
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
|
||||
@@ -14,12 +14,17 @@
|
||||
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',
|
||||
@@ -51,8 +56,11 @@
|
||||
|
||||
let table = createSvelteTable(options)
|
||||
|
||||
const { worldStore, staticOutputs: staticOutputsStore } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
const {
|
||||
app,
|
||||
worldStore,
|
||||
staticOutputs: staticOutputsStore
|
||||
} = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let selectedRowIndex = -1
|
||||
|
||||
@@ -133,13 +141,22 @@
|
||||
}
|
||||
|
||||
$: result && rerender()
|
||||
|
||||
$: css = concatCustomCss($app.css?.tablecomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.search} bind:value={search} />
|
||||
|
||||
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if Array.isArray(result) && result.every(isObject)}
|
||||
<div class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full">
|
||||
<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 ?? ''}
|
||||
>
|
||||
{#if search !== 'Disabled'}
|
||||
<div class="px-2 py-1">
|
||||
<div class="flex items-center">
|
||||
@@ -152,7 +169,14 @@
|
||||
|
||||
<div class="overflow-x-auto flex-1 w-full">
|
||||
<table class="relative w-full border-b border-b-gray-200">
|
||||
<thead class="sticky top-0 z-40 bg-gray-50 text-left">
|
||||
<thead
|
||||
class={twMerge(
|
||||
'bg-gray-50 text-left',
|
||||
css?.tableHeader?.class ?? '',
|
||||
'sticky top-0 z-40'
|
||||
)}
|
||||
style={css?.tableHeader?.style ?? ''}
|
||||
>
|
||||
{#each $table.getHeaderGroups() as headerGroup}
|
||||
<tr class="divide-x">
|
||||
{#each headerGroup.headers as header}
|
||||
@@ -178,7 +202,10 @@
|
||||
</tr>
|
||||
{/each}
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 bg-white ">
|
||||
<tbody
|
||||
class={twMerge('divide-y divide-gray-200 bg-white', css?.tableBody?.class ?? '')}
|
||||
style={css?.tableBody?.style ?? ''}
|
||||
>
|
||||
{#each $table.getRowModel().rows as row, rowIndex (row.id)}
|
||||
<tr
|
||||
class={classNames(
|
||||
@@ -235,7 +262,13 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<AppTableFooter paginationEnabled={pagination} {result} {table} />
|
||||
<AppTableFooter
|
||||
paginationEnabled={pagination}
|
||||
{result}
|
||||
{table}
|
||||
class={css?.tableFooter.class}
|
||||
style={css?.tableFooter.style}
|
||||
/>
|
||||
</div>
|
||||
{:else if result != undefined}
|
||||
<Alert title="Parsing issues" type="error" size="xs">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
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>
|
||||
@@ -11,6 +12,9 @@
|
||||
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))
|
||||
@@ -23,7 +27,10 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="px-2 py-1 text-xs flex flex-row gap-2 items-center justify-between">
|
||||
<div
|
||||
class={twMerge('px-2 py-1 text-xs gap-2 items-center justify-between', c, 'flex flex-row')}
|
||||
{style}
|
||||
>
|
||||
{#if paginationEnabled && result.length > (tableOptions.initialState?.pagination?.pageSize ?? 25)}
|
||||
<div class="flex items-center gap-2 flex-row">
|
||||
<Button
|
||||
|
||||
@@ -1,41 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
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 = classNames(
|
||||
$: classes = twMerge(
|
||||
'flex z-auto',
|
||||
noWFull ? '' : 'w-full',
|
||||
tailwindHorizontalAlignment(horizontalAlignment),
|
||||
tailwindVerticalAlignment(verticalAlignment),
|
||||
verticalAlignment ? 'h-full' : '',
|
||||
$$props.class || ''
|
||||
c
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class={classes}>
|
||||
<div class={classes} {style}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -10,21 +10,17 @@
|
||||
export let input: AppInput
|
||||
export let value: T
|
||||
export let id: string | undefined = undefined
|
||||
export let row: Record<string, any> | undefined = {}
|
||||
export let error: string = ''
|
||||
|
||||
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
$: state = $worldStore?.state
|
||||
$: input && $worldStore && row && handleConnection()
|
||||
$: input && $worldStore && handleConnection()
|
||||
$: input && input.type == 'template' && $state && (value = getValue(input))
|
||||
$: input && input.type == 'eval' && $state && (value = evalExpr(input))
|
||||
|
||||
function handleConnection() {
|
||||
if (input.type === 'connected') {
|
||||
$worldStore?.connect<any>(input, onValueChange)
|
||||
} else if (input.type === 'row') {
|
||||
setTimeout(() => (value = row?.[input['column']]), 0)
|
||||
} else if (input.type === 'static' || input.type == 'template') {
|
||||
setTimeout(() => (value = getValue(input)), 0)
|
||||
} else if (input.type == 'eval') {
|
||||
@@ -57,7 +53,6 @@
|
||||
Object.fromEntries(Object.entries(value ?? {}).map((x) => [x[0], x[1].peak()]))
|
||||
]
|
||||
})
|
||||
.concat(row ? [['row', row]] : [])
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import { AppService, type CompletedJob } from '$lib/gen'
|
||||
import { defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { computeFields } from '../../editor/inlineScriptsPanel/utils'
|
||||
import type { AppInputs, Runnable } from '../../inputType'
|
||||
@@ -25,6 +26,7 @@
|
||||
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
|
||||
|
||||
@@ -37,7 +39,8 @@
|
||||
jobs,
|
||||
noBackend,
|
||||
errorByComponent,
|
||||
mode
|
||||
mode,
|
||||
stateId
|
||||
} = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
onMount(() => {
|
||||
@@ -112,13 +115,11 @@
|
||||
// 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)
|
||||
if (!deepEqual(newFields, fields)) {
|
||||
fields = newFields
|
||||
$stateId++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,12 +240,7 @@
|
||||
|
||||
{#each Object.entries(fields ?? {}) as [key, v]}
|
||||
{#if v.type != 'static' && v.type != 'user'}
|
||||
<InputValue
|
||||
{id}
|
||||
input={fields[key]}
|
||||
bind:value={runnableInputValues[key]}
|
||||
row={extraQueryParams['row'] ?? {}}
|
||||
/>
|
||||
<InputValue {id} input={fields[key]} bind:value={runnableInputValues[key]} />
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -275,7 +271,7 @@
|
||||
bind:this={testJobLoader}
|
||||
/>
|
||||
|
||||
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}">
|
||||
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}" style={wrapperStyle}>
|
||||
{#if !initializing && autoRefresh === true}
|
||||
<div class="flex absolute top-1 right-1">
|
||||
<RefreshButton componentId={id} />
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
export let defaultUserInput = false
|
||||
export let flexWrap = false
|
||||
export let runnableClass = ''
|
||||
export let runnableStyle = ''
|
||||
export let goto: string | undefined = undefined
|
||||
|
||||
const { staticExporter, noBackend } = getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -55,6 +56,7 @@
|
||||
{forceSchemaDisplay}
|
||||
{initializing}
|
||||
wrapperClass={runnableClass}
|
||||
wrapperStyle={runnableStyle}
|
||||
>
|
||||
<slot />
|
||||
</RunnableComponent>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
@@ -11,8 +12,9 @@
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
export const staticOutputs: string[] = ['result']
|
||||
|
||||
@@ -27,6 +29,8 @@
|
||||
}
|
||||
|
||||
$: defaultValue != undefined && outputs?.result.set(defaultValue)
|
||||
|
||||
$: css = concatCustomCss($app.css?.checkboxcomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.label} bind:value={labelValue} />
|
||||
@@ -40,6 +44,8 @@
|
||||
}}
|
||||
checked={defaultValue}
|
||||
options={{ right: labelValue }}
|
||||
textClass={css?.text?.class ?? ''}
|
||||
textStyle={css?.text?.style ?? ''}
|
||||
on:change={(e) => {
|
||||
outputs.result.set(e.detail)
|
||||
}}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<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 } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
@@ -12,8 +14,9 @@
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let input: HTMLInputElement
|
||||
let labelValue: string = 'Title'
|
||||
let minValue: string = ''
|
||||
@@ -29,6 +32,8 @@
|
||||
}
|
||||
|
||||
$: input && handleInput()
|
||||
|
||||
$: css = concatCustomCss($app.css?.dateinputcomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.label} bind:value={labelValue} />
|
||||
@@ -46,6 +51,7 @@
|
||||
min={minValue}
|
||||
max={maxValue}
|
||||
placeholder="Type..."
|
||||
class="h-full"
|
||||
class={twMerge('mx-0.5', css?.input?.class ?? '')}
|
||||
style={css?.input?.style ?? ''}
|
||||
/>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<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 } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let acceptedFileTypes: string[] | undefined = undefined
|
||||
let allowMultiple: boolean | undefined = undefined
|
||||
@@ -24,6 +27,8 @@
|
||||
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} />
|
||||
@@ -38,7 +43,8 @@
|
||||
on:change={({ detail }) => {
|
||||
handleChange(detail)
|
||||
}}
|
||||
class="w-full h-full"
|
||||
class={twMerge('w-full h-full', css?.container?.class)}
|
||||
style={css?.container?.style}
|
||||
>
|
||||
{text}
|
||||
</FileInput>
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
@@ -11,8 +12,9 @@
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let input: HTMLInputElement
|
||||
|
||||
let defaultValue: number | undefined = undefined
|
||||
@@ -33,6 +35,8 @@
|
||||
}
|
||||
|
||||
$: input && handleInput()
|
||||
|
||||
$: css = concatCustomCss($app.css?.numberinputcomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.step} bind:value={step} />
|
||||
@@ -44,6 +48,8 @@
|
||||
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<input
|
||||
class="mx-0.5 {css?.input?.class ?? ''}"
|
||||
style={css?.input?.style ?? ''}
|
||||
bind:this={input}
|
||||
on:input={handleInput}
|
||||
on:focus={(e) => {
|
||||
|
||||
@@ -3,20 +3,24 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import { Badge } from '$lib/components/common'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let min = 0
|
||||
let max = 42
|
||||
let step = 1
|
||||
let slider: HTMLElement
|
||||
|
||||
let values: [number, number] = [0, 0]
|
||||
|
||||
@@ -25,6 +29,17 @@
|
||||
}
|
||||
|
||||
$: 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} />
|
||||
@@ -36,20 +51,45 @@
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="flex items-center w-full gap-1 px-1">
|
||||
<span>{min}</span>
|
||||
<span class={css?.limits?.class ?? ''} style={css?.limits?.style ?? ''}>
|
||||
{min}
|
||||
</span>
|
||||
<div class="grow" on:pointerdown|stopPropagation>
|
||||
<RangeSlider {step} range min={min ?? 0} max={max ?? 1} bind:values />
|
||||
<!-- <DoubleRange bind:start bind:end /> -->
|
||||
<RangeSlider
|
||||
bind:slider
|
||||
bind:values
|
||||
{step}
|
||||
min={min ?? 0}
|
||||
max={max ?? 1}
|
||||
range
|
||||
pips
|
||||
hoverable={false}
|
||||
/>
|
||||
<!-- <RangeSlider {step} range min={min ?? 0} max={max ?? 1} bind:values /> -->
|
||||
</div>
|
||||
<span>{max}</span>
|
||||
<span class={css?.limits?.class ?? ''} style={css?.limits?.style ?? ''}>
|
||||
{max}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-between px-1">
|
||||
<div>
|
||||
<Badge color="blue">{values[0]}</Badge>
|
||||
</div>
|
||||
<div>
|
||||
<Badge color="blue">{values[1]}</Badge>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -3,17 +3,20 @@
|
||||
import Select from 'svelte-select'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
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'
|
||||
|
||||
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 { worldStore, connectingInput, selectedComponent } =
|
||||
const { app, worldStore, connectingInput, selectedComponent } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
let items: { label: string; value: any }[]
|
||||
let multiple: boolean = false
|
||||
@@ -23,7 +26,13 @@
|
||||
result: Output<string | undefined>
|
||||
}
|
||||
|
||||
let value: string | undefined = undefined
|
||||
// $: outputs && handleOutputs()
|
||||
|
||||
// function handleOutputs() {
|
||||
// value = outputs.result.peak()
|
||||
// }
|
||||
|
||||
let value: string | undefined = outputs?.result.peak()
|
||||
|
||||
$: items && handleItems()
|
||||
|
||||
@@ -38,9 +47,15 @@
|
||||
}
|
||||
})
|
||||
: []
|
||||
if (items?.[0]?.['value'] != value) {
|
||||
value = JSON.stringify(items?.[0]?.['value'])
|
||||
outputs?.result.set(value)
|
||||
const valuePeak = outputs?.result.peak()
|
||||
if (!valuePeak) {
|
||||
const value0 = items?.[0]?.['value']
|
||||
if (value0 != value) {
|
||||
value = JSON.stringify(value0)
|
||||
outputs?.result.set(value0)
|
||||
}
|
||||
} else {
|
||||
value = JSON.stringify(valuePeak)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +68,8 @@
|
||||
} catch (_) {}
|
||||
outputs?.result.set(result)
|
||||
}
|
||||
|
||||
$: css = concatCustomCss($app.css?.selectcomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.items} bind:value={items} />
|
||||
@@ -60,13 +77,15 @@
|
||||
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
|
||||
|
||||
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
|
||||
<div class="app-select w-full" style="height: 34px" on:pointerdown|stopPropagation>
|
||||
<div class="app-select w-full mx-0.5" style="height: 34px" on:pointerdown|stopPropagation>
|
||||
<Select
|
||||
--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={() => {
|
||||
@@ -74,6 +93,12 @@
|
||||
$selectedComponent = id
|
||||
}
|
||||
}}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
floatingConfig={{
|
||||
strategy: 'fixed'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</AlignWrapper>
|
||||
@@ -82,4 +107,7 @@
|
||||
.app-select .value-container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.svelte-select-list {
|
||||
z-index: 1000 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,28 +1,35 @@
|
||||
<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 } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } 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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let values: [number] = [0]
|
||||
const { app, worldStore, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let min = 0
|
||||
let max = 42
|
||||
let step = 1
|
||||
let slider: HTMLElement
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
result: Output<number | null>
|
||||
}
|
||||
$: if (values) {
|
||||
|
||||
let values: [number] = [outputs?.result.peak() ?? 0]
|
||||
|
||||
$: values && handleValues()
|
||||
|
||||
function handleValues() {
|
||||
// Disallow 'e' character in numbers
|
||||
// if(value && value.toString().includes('e')) {
|
||||
// value = +value.toString().replaceAll('e', '')
|
||||
@@ -30,6 +37,17 @@
|
||||
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} />
|
||||
@@ -39,11 +57,33 @@
|
||||
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<div class="flex items-center w-full gap-1 px-1">
|
||||
<span>{min}</span>
|
||||
<div class="grow" on:pointerdown|stopPropagation>
|
||||
<RangeSlider {step} min={min ?? 0} max={max ?? 1} bind:values />
|
||||
<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 ?? 0}
|
||||
max={max ?? 1}
|
||||
pips
|
||||
hoverable={false}
|
||||
/>
|
||||
</div>
|
||||
<span>{max}</span>
|
||||
<span class="mx-2"><Badge large color="blue">{values[0]}</Badge></span>
|
||||
<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>
|
||||
</div>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<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 } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
@@ -12,8 +14,10 @@
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let input: HTMLInputElement
|
||||
|
||||
let placeholder: string | undefined = undefined
|
||||
@@ -28,6 +32,8 @@
|
||||
}
|
||||
|
||||
$: input && handleInput()
|
||||
|
||||
$: css = concatCustomCss($app.css?.[appCssKey], customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
|
||||
@@ -36,7 +42,8 @@
|
||||
|
||||
<AlignWrapper {verticalAlignment}>
|
||||
<input
|
||||
class="mx-0.5"
|
||||
class={twMerge('mx-0.5', css?.input?.class ?? '')}
|
||||
style={css?.input?.style ?? ''}
|
||||
on:focus={(e) => {
|
||||
e?.stopPropagation()
|
||||
window.dispatchEvent(new Event('pointerup'))
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../../inputType'
|
||||
import type { Output } from '../../../rx'
|
||||
import type { AppEditorContext } from '../../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../../types'
|
||||
import { concatCustomCss } from '../../../utils'
|
||||
import AlignWrapper from '../../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../../helpers/InputValue.svelte'
|
||||
import CurrencyInput from './CurrencyInput.svelte'
|
||||
@@ -11,8 +12,9 @@
|
||||
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 { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let defaultValue: number | undefined = undefined
|
||||
|
||||
@@ -37,6 +39,8 @@
|
||||
$: value != undefined && handleInput()
|
||||
|
||||
$: defaultValue != undefined && handleDefault()
|
||||
|
||||
$: css = concatCustomCss($app.css?.currencycomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.defaultValue} bind:value={defaultValue} />
|
||||
@@ -49,7 +53,12 @@
|
||||
{#key locale}
|
||||
{#key currency}
|
||||
<CurrencyInput
|
||||
inputClasses={{ formatted: 'p-0', wrapper: 'w-full', formattedZero: 'text-black' }}
|
||||
inputClasses={{
|
||||
formatted: 'p-0 ' + css?.input?.class,
|
||||
wrapper: 'w-full',
|
||||
formattedZero: 'text-black ' + css?.input?.class
|
||||
}}
|
||||
style={css?.input?.style}
|
||||
bind:value
|
||||
{currency}
|
||||
{locale}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
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 = (
|
||||
@@ -175,6 +176,7 @@
|
||||
? inputClasses?.formattedNegative ?? DEFAULT_CLASS_FORMATTED_NEGATIVE
|
||||
: ''}
|
||||
"
|
||||
{style}
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
name={`formatted-${name}`}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS, GridItem } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
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
|
||||
|
||||
@@ -24,6 +26,8 @@
|
||||
}
|
||||
|
||||
$: $selectedComponent === id && onFocus()
|
||||
|
||||
$: css = concatCustomCss($app.css?.containercomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
|
||||
@@ -32,6 +36,9 @@
|
||||
{#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={() => {
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { HorizontalAlignment, VerticalAlignment } from '../../types'
|
||||
import type {
|
||||
AppEditorContext,
|
||||
ComponentCustomCSS,
|
||||
HorizontalAlignment,
|
||||
VerticalAlignment
|
||||
} from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
@@ -8,17 +16,34 @@
|
||||
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="h-full">
|
||||
<AlignWrapper
|
||||
{horizontalAlignment}
|
||||
{verticalAlignment}
|
||||
class={twMerge(css?.container?.class, 'h-full')}
|
||||
style={css?.container?.style}
|
||||
>
|
||||
<div
|
||||
class="rounded-full {position === 'horizontal' ? 'w-full' : 'h-full'}"
|
||||
style="{position === 'horizontal' ? 'height' : 'width'}: {size}px; background-color: {color}"
|
||||
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 ?? ''}
|
||||
"
|
||||
/>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<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}>
|
||||
{#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>
|
||||
@@ -4,14 +4,17 @@
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
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 } =
|
||||
@@ -32,6 +35,15 @@
|
||||
|
||||
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()
|
||||
@@ -46,29 +58,43 @@
|
||||
}
|
||||
|
||||
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
|
||||
|
||||
$: css = concatCustomCss($app.css?.tabscomponent, customCss)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.tabs} bind:value={tabs} />
|
||||
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
|
||||
|
||||
<div>
|
||||
<div bind:clientHeight={tabHeight}>
|
||||
<Tabs bind:selected>
|
||||
<div bind:clientHeight={tabHeight} on:pointerdown|stopPropagation>
|
||||
<Tabs bind:selected class={css?.tabRow?.class} style={css?.tabRow?.style}>
|
||||
{#each tabs ?? [] as res}
|
||||
<Tab value={res}>
|
||||
<Tab
|
||||
value={res}
|
||||
class={css?.tabs?.class}
|
||||
style={css?.tabs?.style}
|
||||
selectedClass={css?.selectedTab?.class}
|
||||
selectedStyle={css?.selectedTab?.style}
|
||||
>
|
||||
<span class="font-semibold">{res}</span>
|
||||
</Tab>
|
||||
{/each}
|
||||
</Tabs>
|
||||
</div>
|
||||
{#if $app.subgrids?.[`${id}-${selectedIndex}`]}
|
||||
<SubGridEditor
|
||||
bind:subGrid={$app.subgrids[`${id}-${selectedIndex}`]}
|
||||
{noPadding}
|
||||
containerHeight={componentContainerHeight - tabHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
/>
|
||||
{#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}
|
||||
</div>
|
||||
|
||||
@@ -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 { encodeState } from '$lib/utils'
|
||||
import { classNames, encodeState } from '$lib/utils'
|
||||
import AppPreview from './AppPreview.svelte'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
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
|
||||
@@ -60,7 +59,6 @@
|
||||
|
||||
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', {
|
||||
@@ -83,7 +81,8 @@
|
||||
noBackend: false,
|
||||
errorByComponent,
|
||||
openDebugRun: writable(undefined),
|
||||
focusedGrid
|
||||
focusedGrid,
|
||||
stateId: writable(0)
|
||||
})
|
||||
|
||||
let timeout: NodeJS.Timeout | undefined = undefined
|
||||
@@ -127,7 +126,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}
|
||||
@@ -173,14 +172,17 @@
|
||||
style={$appStore.css?.['app']?.['viewer']?.style}
|
||||
>
|
||||
<div
|
||||
class="relative mx-auto w-full h-full overflow-auto {app.fullscreen
|
||||
? ''
|
||||
: 'max-w-6xl'}"
|
||||
class={classNames(
|
||||
'relative mx-auto w-full h-full overflow-auto',
|
||||
app.fullscreen ? '' : 'max-w-6xl'
|
||||
)}
|
||||
>
|
||||
{#if $appStore.grid}
|
||||
<div class={width}>
|
||||
<GridEditor {policy} />
|
||||
</div>
|
||||
|
||||
<div id="app-editor-top-level-drawer" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
UserAppInput
|
||||
} from '../inputType'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import { toStatic } from '../utils'
|
||||
import { allItems, 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(
|
||||
$app.grid
|
||||
allItems($app.grid, $app.subgrids)
|
||||
.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-hidden">
|
||||
<div class="h-full w-full overflow-auto">
|
||||
{#if selectedJobId}
|
||||
{#if !job}
|
||||
<Skeleton layout={[[40]]} />
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
noBackend,
|
||||
errorByComponent: writable({}),
|
||||
openDebugRun: writable(undefined),
|
||||
focusedGrid: writable(undefined)
|
||||
focusedGrid: writable(undefined),
|
||||
stateId: writable(0)
|
||||
})
|
||||
|
||||
let mounted = false
|
||||
@@ -76,6 +77,8 @@
|
||||
$: lockedClasses = isLocked ? '!max-h-[400px] overflow-hidden pointer-events-none' : ''
|
||||
</script>
|
||||
|
||||
<div id="app-editor-top-level-drawer" />
|
||||
|
||||
<div class="relative">
|
||||
<div
|
||||
class="{$$props.class} {lockedClasses} h-full
|
||||
@@ -87,6 +90,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if isLocked}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
$app.grid.map((gridItem) => {
|
||||
const disabledGridItem = fct(gridItem)
|
||||
|
||||
if (disabledGridItem.data.subGrids) {
|
||||
if (disabledGridItem?.data?.subGrids) {
|
||||
disabledGridItem.data.subGrids = disabledGridItem.data.subGrids.map(
|
||||
(subgrid: GridItem[]) => subgrid?.map((subgridItem: GridItem) => fct(subgridItem)) ?? []
|
||||
)
|
||||
@@ -44,6 +44,10 @@
|
||||
|
||||
return disabledGridItem
|
||||
})
|
||||
|
||||
Object.values($app.subgrids ?? {}).map(
|
||||
(subgrid: GridItem[]) => subgrid?.map((subgridItem: GridItem) => fct(subgridItem)) ?? []
|
||||
)
|
||||
}
|
||||
|
||||
function removeGridElement(component) {
|
||||
@@ -102,7 +106,7 @@
|
||||
intervalId = setTimeout(() => {
|
||||
lazyGrid.set($app.grid)
|
||||
intervalId = undefined
|
||||
}, 100)
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,12 +131,11 @@
|
||||
})
|
||||
}
|
||||
})
|
||||
let mounted = false
|
||||
</script>
|
||||
|
||||
<div class="relative w-full z-20 overflow-visible">
|
||||
<div
|
||||
class="w-full sticky top-0 flex justify-between border-l border-r border-b {$connectingInput?.opened
|
||||
class="w-full sticky top-0 flex justify-between border-l border-r border-b {$connectingInput?.opened
|
||||
? ''
|
||||
: 'bg-gray-50 '} px-4 py-2 items-center gap-4"
|
||||
style="z-index: 1000;"
|
||||
@@ -146,14 +149,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
style={$app.css?.['app']?.['grid']?.style}
|
||||
class={twMerge('px-4 pt-4 pb-2 overflow-visible', $app.css?.['app']?.['grid']?.class ?? '')}
|
||||
class={twMerge('px-4 pt-4 pb-2 overflow-visible', $app.css?.['app']?.['grid']?.class ?? '')}
|
||||
on:pointerdown={onpointerdown}
|
||||
on:pointerleave={onpointerup}
|
||||
on:pointerup={onpointerup}
|
||||
on:click={() => {
|
||||
$selectedComponent = undefined
|
||||
$focusedGrid = undefined
|
||||
}}
|
||||
>
|
||||
<Grid
|
||||
onTopId={$selectedComponent}
|
||||
fillSpace={false}
|
||||
bind:items={$app.grid}
|
||||
let:dataItem
|
||||
@@ -166,13 +175,11 @@
|
||||
{#if gridComponent.data.id === dataItem.data.id}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
{#if $connectingInput.opened}
|
||||
{#if $connectingInput.opened}
|
||||
<div
|
||||
on:pointerenter={() => ($connectingInput.hoveredComponent = gridComponent.data.id)}
|
||||
on:pointerleave={() => ($connectingInput.hoveredComponent = undefined)}
|
||||
class="absolute w-full h-full bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
|
||||
/>
|
||||
{/if}
|
||||
<div
|
||||
on:pointerenter={() => ($connectingInput.hoveredComponent = gridComponent.data.id)}
|
||||
on:pointerleave={() => ($connectingInput.hoveredComponent = undefined)}
|
||||
class="absolute w-full h-full bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
|
||||
/>
|
||||
<div
|
||||
style="transform: translate(-50%, -50%);"
|
||||
class="absolute w-fit justify-center bg-indigo-500/90 left-[50%] top-[50%] z-50 px-6 rounded border text-white py-2 text-5xl center-center"
|
||||
@@ -181,6 +188,7 @@
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
on:click|stopPropagation
|
||||
on:pointerdown={() => selectComponent(dataItem.data.id)}
|
||||
class={classNames(
|
||||
'h-full w-full center-center',
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import TablePanel from './TablePanel.svelte'
|
||||
|
||||
const { selectedComponent, app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
$: subgridKeys = Object.keys($app.subgrids ?? {})
|
||||
</script>
|
||||
|
||||
{#each $app.grid as gridItem (gridItem.data.id)}
|
||||
@@ -20,7 +19,7 @@
|
||||
{/each}
|
||||
|
||||
{#if $app.subgrids}
|
||||
{#each subgridKeys as key (key)}
|
||||
{#each Object.keys($app.subgrids ?? {}) as key (key)}
|
||||
{#each $app.subgrids[key] as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel parent={key} bind:component={gridItem.data} />
|
||||
|
||||
@@ -2,22 +2,29 @@
|
||||
import { classNames } from '$lib/utils'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import Grid from '@windmill-labs/svelte-grid'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { columnConfiguration, isFixed, toggleFixed } from '../gridUtils'
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
import Component from './component/Component.svelte'
|
||||
import { findGridItem } from './appUtils'
|
||||
|
||||
export let containerHeight: number
|
||||
let classes = ''
|
||||
export { classes as class }
|
||||
export let style = ''
|
||||
export let noPadding = false
|
||||
//export let id: string
|
||||
export let subGrid: GridItem[] = []
|
||||
export let visible: boolean = true
|
||||
export let id: string
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const { app, connectingInput, selectedComponent, focusedGrid } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let pointerdown = false
|
||||
$: highlight = id === $focusedGrid?.parentComponentId && $selectedComponent !== id
|
||||
|
||||
let pointerdown = false
|
||||
let onComponent: string | undefined = undefined
|
||||
|
||||
const onpointerdown = (e) => {
|
||||
@@ -47,7 +54,7 @@
|
||||
}
|
||||
|
||||
function lock(gridComponent: GridItem) {
|
||||
let fComponent = $app.grid.find((c) => c.id === gridComponent.id)
|
||||
let fComponent = findGridItem($app, gridComponent.data.id)
|
||||
if (fComponent) {
|
||||
fComponent = toggleFixed(fComponent)
|
||||
}
|
||||
@@ -57,14 +64,21 @@
|
||||
let container
|
||||
</script>
|
||||
|
||||
<div class="relative w-full subgrid " bind:this={container}>
|
||||
<div
|
||||
class="relative w-full subgrid {visible ? 'visible' : 'invisible h-0 overflow-hidden'} "
|
||||
bind:this={container}
|
||||
>
|
||||
<div
|
||||
class:px-2={!noPadding}
|
||||
class="py-2 overflow-auto {$connectingInput?.opened ? '' : ''}"
|
||||
class={twMerge(
|
||||
'py-2 overflow-auto',
|
||||
classes ?? '',
|
||||
noPadding ? 'px-0' : 'px-2',
|
||||
highlight ? 'border-indigo-500 border border-dashed' : ''
|
||||
)}
|
||||
on:pointerdown|stopPropagation={onpointerdown}
|
||||
on:pointerleave={onpointerup}
|
||||
on:pointerup={onpointerup}
|
||||
style="height: {containerHeight}px;"
|
||||
style="height: {containerHeight}px; {style ?? ''}"
|
||||
>
|
||||
<div>
|
||||
<Grid
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getNextId } from '$lib/components/flows/flowStateUtils'
|
||||
import type { App, FocusedGrid, GridItem } from '../types'
|
||||
import { Component, getRecommendedDimensionsByComponent, type AppComponent } from './component'
|
||||
import { getRecommendedDimensionsByComponent, type AppComponent } from './component'
|
||||
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
|
||||
import { gridColumns } from '../gridUtils'
|
||||
import { allItems } from '../utils'
|
||||
@@ -10,27 +10,11 @@ function findGridItemById(
|
||||
subGrids: Record<string, GridItem[]> | undefined,
|
||||
id: string
|
||||
): GridItem | undefined {
|
||||
for (const gridItem of root) {
|
||||
for (const gridItem of allItems(root, subGrids)) {
|
||||
if (gridItem.id === id) {
|
||||
return gridItem
|
||||
}
|
||||
|
||||
if (subGrids) {
|
||||
const numberOfSubgrids = gridItem.data.numberOfSubgrids
|
||||
|
||||
if (numberOfSubgrids) {
|
||||
for (let i = 0; i < numberOfSubgrids; i++) {
|
||||
const subgrid = subGrids[`${gridItem.id}-${i}`] ?? []
|
||||
const found = findGridItemById(subgrid, subGrids, id)
|
||||
|
||||
if (found) {
|
||||
return found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
@@ -88,9 +72,14 @@ export function createNewGridItem(grid: GridItem[], id: string, data: AppCompone
|
||||
export function insertNewGridItem(
|
||||
app: App,
|
||||
data: AppComponent,
|
||||
focusedGrid: FocusedGrid | undefined
|
||||
focusedGrid: FocusedGrid | undefined,
|
||||
keepId?: boolean
|
||||
) {
|
||||
const id = getNextGridItemId(app)
|
||||
const id = keepId ? data.id : getNextGridItemId(app)
|
||||
|
||||
if (!app.subgrids) {
|
||||
app.subgrids = {}
|
||||
}
|
||||
|
||||
if (!focusedGrid) {
|
||||
const newItem = createNewGridItem(app.grid, id, data)
|
||||
@@ -98,18 +87,16 @@ export function insertNewGridItem(
|
||||
} else {
|
||||
const { parentComponentId, subGridIndex } = focusedGrid
|
||||
|
||||
if (!app.subgrids) {
|
||||
app.subgrids = {}
|
||||
}
|
||||
|
||||
const subGrid = app.subgrids[`${parentComponentId}-${subGridIndex}`] ?? []
|
||||
const newItem = createNewGridItem(subGrid, id, data)
|
||||
const key = `${parentComponentId}-${subGridIndex ?? 0}`
|
||||
|
||||
if (!app.subgrids[key]) {
|
||||
app.subgrids[key] = [newItem]
|
||||
} else {
|
||||
app.subgrids[key].push(newItem)
|
||||
const subGrid = app.subgrids[key] ?? []
|
||||
subGrid.push(createNewGridItem(subGrid, id, data))
|
||||
app.subgrids[key] = subGrid
|
||||
}
|
||||
// We only want to set subgrids when we are not moving
|
||||
if (!keepId) {
|
||||
for (let i = 0; i < (data.numberOfSubgrids ?? 0); i++) {
|
||||
app.subgrids[`${id}-${i}`] = []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +111,10 @@ export function getAllSubgridsAndComponentIds(
|
||||
let components: string[] = [component.id]
|
||||
if (app.subgrids && component.numberOfSubgrids) {
|
||||
for (let i = 0; i < component.numberOfSubgrids; i++) {
|
||||
const subgrid = app.subgrids[`${component.id}-${i}`]
|
||||
const key = `${component.id}-${i}`
|
||||
const subgrid = app.subgrids[key]
|
||||
if (subgrid) {
|
||||
subgrids.push(key)
|
||||
for (const item of subgrid) {
|
||||
let [recSubgrids, recComponents] = getAllSubgridsAndComponentIds(app, item.data)
|
||||
subgrids.push(...recSubgrids)
|
||||
@@ -140,10 +129,11 @@ export function getAllSubgridsAndComponentIds(
|
||||
export function deleteGridItem(
|
||||
app: App,
|
||||
component: AppComponent,
|
||||
parent: string | undefined
|
||||
parent: string | undefined,
|
||||
shouldKeepSubGrid: boolean
|
||||
): string[] {
|
||||
let [subgrids, components] = getAllSubgridsAndComponentIds(app, component)
|
||||
if (app.subgrids) {
|
||||
if (app.subgrids && !shouldKeepSubGrid) {
|
||||
subgrids.forEach((id) => {
|
||||
delete app.subgrids![id]
|
||||
})
|
||||
@@ -166,16 +156,21 @@ export function deleteGridItem(
|
||||
|
||||
export function duplicateGridItem(
|
||||
app: App,
|
||||
focusedGrid: FocusedGrid | undefined,
|
||||
parent: string | undefined,
|
||||
id: string
|
||||
): string | undefined {
|
||||
const gridItem = findGridItem(app, id)
|
||||
|
||||
if (gridItem) {
|
||||
const newId = getNextGridItemId(app)
|
||||
const newItem = JSON.parse(JSON.stringify(gridItem))
|
||||
newItem.id = newId
|
||||
newItem.data.id = newId
|
||||
|
||||
let focusedGrid = parent
|
||||
? { parentComponentId: parent.split('-')[0], subGridIndex: Number(parent.split('-')[1]) }
|
||||
: undefined
|
||||
|
||||
return insertNewGridItem(app, newItem.data, focusedGrid)
|
||||
}
|
||||
return undefined
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import ComponentHeader from '../ComponentHeader.svelte'
|
||||
|
||||
import {
|
||||
AppBarChart,
|
||||
AppDisplayComponent,
|
||||
@@ -35,6 +36,8 @@
|
||||
AppContainer
|
||||
} from '../../components'
|
||||
import type { AppComponent } from './components'
|
||||
import AppAggridTable from '../../components/display/table/AppAggridTable.svelte'
|
||||
import AppDrawer from '../../components/layout/AppDrawer.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
@@ -46,6 +49,8 @@
|
||||
let hover = false
|
||||
let initializing: boolean | undefined = undefined
|
||||
let componentContainerHeight: number = 0
|
||||
|
||||
$: console.log('component', component)
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -143,6 +148,13 @@
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:actionButtons={component.actionButtons}
|
||||
/>
|
||||
{:else if component.type === 'aggridcomponent'}
|
||||
<AppAggridTable
|
||||
{...component}
|
||||
bind:initializing
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
bind:componentInput={component.componentInput}
|
||||
/>
|
||||
{:else if component.type === 'textcomponent'}
|
||||
<AppText
|
||||
{...component}
|
||||
@@ -177,6 +189,7 @@
|
||||
{:else if component.type === 'passwordinputcomponent'}
|
||||
<AppTextInput
|
||||
inputType="password"
|
||||
appCssKey="passwordinputcomponent"
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
@@ -216,6 +229,8 @@
|
||||
<AppFileInput {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'imagecomponent'}
|
||||
<AppImage {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'drawercomponent'}
|
||||
<AppDrawer {...component} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,8 @@ import {
|
||||
SeparatorHorizontal,
|
||||
SeparatorVertical,
|
||||
Paperclip,
|
||||
Image
|
||||
Image,
|
||||
SidebarClose
|
||||
} from 'lucide-svelte'
|
||||
import type { BaseAppComponent } from '../../types'
|
||||
|
||||
@@ -63,6 +64,7 @@ export type ScatterChartComponent = BaseComponent<'scatterchartcomponent'>
|
||||
export type TableComponent = BaseComponent<'tablecomponent'> & {
|
||||
actionButtons: (BaseAppComponent & ButtonComponent)[]
|
||||
}
|
||||
export type AggridComponent = BaseComponent<'aggridcomponent'>
|
||||
export type DisplayComponent = BaseComponent<'displaycomponent'>
|
||||
export type ImageComponent = BaseComponent<'imagecomponent'>
|
||||
export type InputComponent = BaseComponent<'inputcomponent'>
|
||||
@@ -77,6 +79,7 @@ export type TabsComponent = BaseComponent<'tabscomponent'> & {
|
||||
tabs: string[]
|
||||
}
|
||||
export type ContainerComponent = BaseComponent<'containercomponent'>
|
||||
export type DrawerComponent = BaseComponent<'drawercomponent'>
|
||||
|
||||
export type AppComponent = BaseAppComponent &
|
||||
(
|
||||
@@ -110,6 +113,8 @@ export type AppComponent = BaseAppComponent &
|
||||
| VerticalDividerComponent
|
||||
| FileInputComponent
|
||||
| ImageComponent
|
||||
| AggridComponent
|
||||
| DrawerComponent
|
||||
)
|
||||
|
||||
export type AppComponentDimensions = `${IntRange<
|
||||
@@ -173,6 +178,9 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
numberOfSubgrids: 1
|
||||
@@ -334,7 +342,10 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
value: ''
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' },
|
||||
button: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true
|
||||
}
|
||||
},
|
||||
@@ -375,7 +386,10 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
optionValuesKey: 'buttonSizeOptions'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
button: { class: '', style: '' },
|
||||
popup: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true
|
||||
}
|
||||
},
|
||||
@@ -406,7 +420,9 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
fieldType: 'object',
|
||||
value: { data: [25, 50, 25], labels: ['Pie', 'Charts', '<3'] }
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true
|
||||
}
|
||||
},
|
||||
@@ -437,7 +453,9 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
fieldType: 'object',
|
||||
value: { data: [25, 50, 25], labels: ['Bar', 'Charts', '<3'] }
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true
|
||||
}
|
||||
},
|
||||
@@ -460,7 +478,9 @@ Hello \${ctx.username}
|
||||
</h1>`
|
||||
},
|
||||
configuration: {},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -602,7 +622,9 @@ Hello \${ctx.username}
|
||||
}
|
||||
]
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true
|
||||
}
|
||||
},
|
||||
@@ -652,7 +674,9 @@ Hello \${ctx.username}
|
||||
}
|
||||
]
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true
|
||||
}
|
||||
},
|
||||
@@ -689,11 +713,70 @@ Hello \${ctx.username}
|
||||
}
|
||||
]
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' },
|
||||
tableHeader: { class: '', style: '' },
|
||||
tableBody: { class: '', style: '' },
|
||||
tableFooter: { class: '', style: '' }
|
||||
} as const,
|
||||
card: true,
|
||||
actionButtons: []
|
||||
}
|
||||
},
|
||||
aggridcomponent: {
|
||||
name: 'AgGrid Table',
|
||||
icon: Table2,
|
||||
dims: '3:10-6:10',
|
||||
data: {
|
||||
id: '',
|
||||
type: 'aggridcomponent',
|
||||
configuration: {
|
||||
columnDefs: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [{ field: 'id' }, { field: 'name', editable: true }, { field: 'age' }]
|
||||
},
|
||||
allEditable: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
onlyStatic: true
|
||||
},
|
||||
pagination: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
onlyStatic: true
|
||||
},
|
||||
pageSize: {
|
||||
type: 'static',
|
||||
fieldType: 'number',
|
||||
value: 10,
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'A cell with a long name',
|
||||
age: 42
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'A briefer cell',
|
||||
age: 84
|
||||
}
|
||||
]
|
||||
},
|
||||
customCss: {},
|
||||
card: true
|
||||
}
|
||||
},
|
||||
checkboxcomponent: {
|
||||
name: 'Toggle',
|
||||
icon: ToggleLeft,
|
||||
@@ -716,7 +799,9 @@ Hello \${ctx.username}
|
||||
fieldType: 'boolean'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
text: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -743,7 +828,9 @@ Hello \${ctx.username}
|
||||
fieldType: 'text'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
input: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -779,7 +866,9 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
input: { style: '' }
|
||||
} as const,
|
||||
card: false,
|
||||
softWrap: true
|
||||
}
|
||||
@@ -809,23 +898,22 @@ Hello \${ctx.username}
|
||||
min: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
max: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
step: {
|
||||
type: 'static',
|
||||
value: 1,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
input: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -866,7 +954,9 @@ Hello \${ctx.username}
|
||||
optionValuesKey: 'localeOptions'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
input: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -890,23 +980,24 @@ Hello \${ctx.username}
|
||||
max: {
|
||||
type: 'static',
|
||||
value: 42,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
defaultValue: {
|
||||
type: 'static',
|
||||
value: 20,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
step: {
|
||||
type: 'static',
|
||||
value: 1,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
handle: { style: '' },
|
||||
limits: { class: '', style: '' },
|
||||
value: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -924,35 +1015,34 @@ Hello \${ctx.username}
|
||||
min: {
|
||||
type: 'static',
|
||||
value: 0,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
max: {
|
||||
type: 'static',
|
||||
value: 42,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
defaultLow: {
|
||||
type: 'static',
|
||||
value: 10,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
defaultHigh: {
|
||||
type: 'static',
|
||||
value: 20,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
},
|
||||
step: {
|
||||
type: 'static',
|
||||
value: 1,
|
||||
fieldType: 'number',
|
||||
onlyStatic: true
|
||||
fieldType: 'number'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
handles: { style: '' },
|
||||
limits: { class: '', style: '' },
|
||||
values: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -974,7 +1064,9 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
input: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -1005,7 +1097,9 @@ Hello \${ctx.username}
|
||||
fieldType: 'date'
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
input: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -1025,6 +1119,12 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {
|
||||
tabRow: { class: '', style: '' },
|
||||
allTabs: { class: '', style: '' },
|
||||
selectedTab: { class: '', style: '' },
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
numberOfSubgrids: 2,
|
||||
@@ -1066,7 +1166,10 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' },
|
||||
icon: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -1093,7 +1196,10 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' },
|
||||
divider: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -1120,7 +1226,10 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' },
|
||||
divider: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -1153,7 +1262,9 @@ Hello \${ctx.username}
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
@@ -1188,16 +1299,71 @@ Hello \${ctx.username}
|
||||
fieldType: 'text',
|
||||
onlyStatic: true,
|
||||
tooltip: "This text will appear if the image can't be loaded for any reason"
|
||||
},
|
||||
customStyles: {
|
||||
type: 'static',
|
||||
value: '',
|
||||
fieldType: 'textarea',
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
customCss: {
|
||||
image: { class: '', style: '' }
|
||||
} as const,
|
||||
card: false
|
||||
}
|
||||
},
|
||||
drawercomponent: {
|
||||
name: 'Drawer',
|
||||
icon: SidebarClose,
|
||||
dims: '1:1-2:1',
|
||||
data: {
|
||||
softWrap: true,
|
||||
id: '',
|
||||
type: 'drawercomponent',
|
||||
horizontalAlignment: 'center',
|
||||
verticalAlignment: 'center',
|
||||
configuration: {
|
||||
noPadding: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
onlyStatic: true
|
||||
},
|
||||
drawerTitle: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
value: 'Drawer title',
|
||||
onlyStatic: true
|
||||
},
|
||||
label: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
value: 'Press me'
|
||||
},
|
||||
color: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'buttonColorOptions',
|
||||
value: 'blue'
|
||||
},
|
||||
size: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
optionValuesKey: 'buttonSizeOptions',
|
||||
value: 'xs'
|
||||
},
|
||||
fillContainer: {
|
||||
fieldType: 'boolean',
|
||||
type: 'static',
|
||||
onlyStatic: true,
|
||||
value: false
|
||||
},
|
||||
disabled: {
|
||||
fieldType: 'boolean',
|
||||
type: 'eval',
|
||||
expr: 'false'
|
||||
}
|
||||
},
|
||||
componentInput: undefined,
|
||||
card: false,
|
||||
numberOfSubgrids: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ const layout: ComponentSet = {
|
||||
'tabscomponent',
|
||||
'containercomponent',
|
||||
'horizontaldividercomponent',
|
||||
'verticaldividercomponent'
|
||||
'verticaldividercomponent',
|
||||
'drawercomponent'
|
||||
]
|
||||
} as const
|
||||
|
||||
@@ -39,14 +40,15 @@ const display: ComponentSet = {
|
||||
'imagecomponent',
|
||||
'htmlcomponent',
|
||||
'tablecomponent',
|
||||
'aggridcomponent',
|
||||
'barchartcomponent',
|
||||
'piechartcomponent',
|
||||
'vegalitecomponent',
|
||||
'plotlycomponent',
|
||||
'scatterchartcomponent',
|
||||
'timeseriescomponent',
|
||||
'displaycomponent',
|
||||
'displaycomponent'
|
||||
]
|
||||
} as const
|
||||
|
||||
export const COMPONENT_SETS = [layout, buttons, inputs, display] as const
|
||||
export const COMPONENT_SETS = [layout, buttons, inputs, display] as const
|
||||
|
||||
@@ -1,34 +1,59 @@
|
||||
<script lang="ts">
|
||||
import type { ComponentCssProperty } from "../../types"
|
||||
import { X } from 'lucide-svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { addWhitespaceBeforeCapitals } from '../../../../utils'
|
||||
import type { ComponentCssProperty } from '../../types'
|
||||
|
||||
export let name: string
|
||||
export let value: ComponentCssProperty | undefined
|
||||
|
||||
function reset(property: keyof ComponentCssProperty) {
|
||||
if (value) {
|
||||
value[property] = ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="text-sm font-semibold text-gray-500 capitalize pt-2">
|
||||
{name}
|
||||
{addWhitespaceBeforeCapitals(name)}
|
||||
</div>
|
||||
{#if value}
|
||||
<div class="border-l border-gray-400/80 py-1 pl-3.5 mt-1 ml-0.5">
|
||||
<label class="block pb-2">
|
||||
<div class="text-xs font-medium pb-0.5">
|
||||
Style
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={value.style}
|
||||
on:focus
|
||||
/>
|
||||
</label>
|
||||
<label class="block">
|
||||
<div class="text-xs font-medium pb-0.5">
|
||||
Tailwind classes
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={value.class}
|
||||
on:focus
|
||||
/>
|
||||
</label>
|
||||
{#if value.style !== undefined}
|
||||
<label class="block pb-2">
|
||||
<div class="text-xs font-medium pb-0.5"> Style </div>
|
||||
<div class="relative">
|
||||
<input type="text" class="!pr-7" bind:value={value.style} on:focus />
|
||||
{#if value?.style}
|
||||
<button
|
||||
transition:fade={{ duration: 100 }}
|
||||
class="absolute z-10 top-1.5 right-1 rounded-full p-1 duration-200 hover:bg-gray-200"
|
||||
aria-label="Remove styles"
|
||||
on:click|preventDefault|stopPropagation={() => reset('style')}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</label>
|
||||
{/if}
|
||||
{#if value.class !== undefined}
|
||||
<label class="block">
|
||||
<div class="text-xs font-medium pb-0.5"> Tailwind classes </div>
|
||||
<div class="relative">
|
||||
<input type="text" class="!pr-7" bind:value={value.class} on:focus />
|
||||
{#if value?.class}
|
||||
<button
|
||||
transition:fade={{ duration: 100 }}
|
||||
class="absolute z-10 top-1.5 right-1 rounded-full p-1 duration-200 hover:bg-gray-200"
|
||||
aria-label="Remove classes"
|
||||
on:click|preventDefault|stopPropagation={() => reset('class')}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -9,15 +9,21 @@
|
||||
import { isOpenStore } from './store'
|
||||
import CssProperty from './CssProperty.svelte'
|
||||
import { components, type AppComponent } from '../component'
|
||||
import { slide } from 'svelte/transition'
|
||||
|
||||
const STATIC_ELEMENTS = ['app'] as const
|
||||
const TITLE_PREFIX = 'Css.' as const
|
||||
const SHOW_UNUSED_ID = 'Setting.ShowUnused' as const
|
||||
|
||||
type CustomCSSType = (typeof STATIC_ELEMENTS)[number] | AppComponent['type']
|
||||
|
||||
interface CustomCSSEntry {
|
||||
type: 'app' | AppComponent['type'];
|
||||
name: string;
|
||||
icon: any;
|
||||
ids: string[];
|
||||
type: CustomCSSType
|
||||
name: string
|
||||
icon: any
|
||||
ids: string[]
|
||||
}
|
||||
|
||||
const TITLE_PREFIX = 'Css.' as const
|
||||
const { app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let rawCode = ''
|
||||
@@ -51,7 +57,7 @@
|
||||
icon: LayoutDashboardIcon,
|
||||
ids: ['viewer', 'grid', 'component']
|
||||
},
|
||||
...Object.values(components).map(({ name, icon, data: { type, customCss }}) => ({
|
||||
...Object.values(components).map(({ name, icon, data: { type, customCss } }) => ({
|
||||
type,
|
||||
name,
|
||||
icon,
|
||||
@@ -70,7 +76,7 @@
|
||||
}
|
||||
e.ids.forEach((id) => {
|
||||
if (!newCss[e.type][id]) {
|
||||
newCss[e.type][id] = { style: '', class: '' }
|
||||
newCss[e.type][id] = components?.[e.type]?.data?.customCss?.[id] ?? { class: '', style: '' }
|
||||
}
|
||||
})
|
||||
e.ids
|
||||
@@ -84,20 +90,32 @@
|
||||
//@ts-ignore
|
||||
$app.css = newCss
|
||||
|
||||
$: staticComponents = entries.filter(({ type }) => STATIC_ELEMENTS.includes(type as any))
|
||||
$: usedComponents = Object.keys(
|
||||
$app.grid.reduce((acc, { data }) => {
|
||||
acc[data.type] = true
|
||||
return acc
|
||||
}, {})
|
||||
)
|
||||
.map((type) => entries.find((entry) => entry.type === type))
|
||||
.filter(Boolean) as CustomCSSEntry[]
|
||||
$: unusedComponents = entries.filter(({ type }) => {
|
||||
return (
|
||||
!STATIC_ELEMENTS.includes(type as any) && !usedComponents.find((entry) => entry.type === type)
|
||||
)
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
isOpenStore.addItems(
|
||||
[{ name: 'App' }, ...Object.values(components)].map(component => {
|
||||
[{ name: 'App' }, ...Object.values(components)].map((component) => {
|
||||
return { [TITLE_PREFIX + component.name]: false }
|
||||
})
|
||||
)
|
||||
isOpenStore.addItems([{ [SHOW_UNUSED_ID]: false }])
|
||||
})
|
||||
</script>
|
||||
|
||||
<Tabs
|
||||
selected="ui"
|
||||
on:selected={(e) => switchTab(e.detail === 'json')}
|
||||
class="relative"
|
||||
>
|
||||
<Tabs selected="ui" on:selected={(e) => switchTab(e.detail === 'json')} class="relative">
|
||||
<Tab value="ui" size="xs" class="grow">
|
||||
<div class="m-1 center-center">
|
||||
<MousePointer2 size={16} />
|
||||
@@ -112,7 +130,7 @@
|
||||
</Tab>
|
||||
<div slot="content" class="h-full overflow-y-auto">
|
||||
<TabContent value="ui">
|
||||
{#each entries as { type, name, icon, ids }}
|
||||
{#each [...staticComponents, ...usedComponents] as { type, name, icon, ids }}
|
||||
{#if ids.length > 0}
|
||||
<ListItem title={name} prefix={TITLE_PREFIX}>
|
||||
<div slot="title" class="flex items-center">
|
||||
@@ -137,6 +155,43 @@
|
||||
</ListItem>
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="px-1 my-4">
|
||||
<button
|
||||
on:click|preventDefault|stopPropagation={() => isOpenStore.toggle(SHOW_UNUSED_ID)}
|
||||
class="w-full text-xs text-gray-500 text-center font-medium hover:underline p-2"
|
||||
>
|
||||
{$isOpenStore[SHOW_UNUSED_ID] ? 'Hide' : 'Show'} unused components
|
||||
</button>
|
||||
</div>
|
||||
{#if $isOpenStore[SHOW_UNUSED_ID]}
|
||||
<div transition:slide|local={{ duration: 300 }}>
|
||||
{#each unusedComponents as { type, name, icon, ids }}
|
||||
{#if ids.length > 0}
|
||||
<ListItem title={name} prefix={TITLE_PREFIX}>
|
||||
<div slot="title" class="flex items-center">
|
||||
<svelte:component this={icon} size={18} />
|
||||
<span class="ml-1">
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
{#each ids as id}
|
||||
<div class="mb-3">
|
||||
{#if $app?.css?.[type][id]}
|
||||
<CssProperty
|
||||
name={id}
|
||||
bind:value={$app.css[type][id]}
|
||||
on:focus={() => (isCustom[type] = true)}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</ListItem>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</TabContent>
|
||||
<TabContent value="json">
|
||||
{#if !emptyString(jsonError)}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
$: isOpen = $isOpenStore[storeTitle]
|
||||
</script>
|
||||
|
||||
<section class="mt-1 mb-2 px-1">
|
||||
<section class="pt-1 pb-2 px-1">
|
||||
<button
|
||||
on:click|preventDefault={() => isOpenStore.toggle(storeTitle)}
|
||||
class="w-full flex justify-between items-center text-gray-700 px-2 py-1
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<script lang="ts">
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import type { Preview } from '$lib/gen'
|
||||
import { faTrash } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher, getContext, onMount } from 'svelte'
|
||||
import type { AppEditorContext, InlineScript } from '../../types'
|
||||
import { CheckCircle, Code2, Maximize2, Trash2, X } from 'lucide-svelte'
|
||||
import { CheckCircle, Maximize2, Trash2, X } from 'lucide-svelte'
|
||||
import InlineScriptEditorDrawer from './InlineScriptEditorDrawer.svelte'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import type { Schema } from '$lib/common'
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import EmptyInlineScript from './EmptyInlineScript.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
import { computeFields } from './utils'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
export let componentInput: AppInput | undefined
|
||||
export let id: string
|
||||
@@ -43,7 +44,7 @@
|
||||
|
||||
async function refreshScript(x: RunnableByPath) {
|
||||
let { schema } = await getScriptByPath(x.path)
|
||||
if (JSON.stringify(x.schema) != JSON.stringify(schema)) {
|
||||
if (!deepEqual(x.schema, schema)) {
|
||||
x.schema = schema
|
||||
if (componentInput?.type == 'runnable') {
|
||||
componentInput.fields = computeFields(schema, false, componentInput.fields)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import InlineScriptsPanelList from './InlineScriptsPanelList.svelte'
|
||||
import InlineScriptEditor from './InlineScriptEditor.svelte'
|
||||
import EmptyInlineScript from './EmptyInlineScript.svelte'
|
||||
import { allItems } from '../../utils'
|
||||
import InlineScriptEditorPanel from './InlineScriptEditorPanel.svelte'
|
||||
|
||||
const { app, staticOutputs, runnableComponents } =
|
||||
@@ -22,10 +21,12 @@
|
||||
</Pane>
|
||||
<Pane size={75}>
|
||||
{#if !selectedScriptComponentId}
|
||||
<span class="p-2 text-sm text-gray-600">Select a script on the left panel</span>
|
||||
<div class="text-sm text-gray-500 text-center py-8 px-2">
|
||||
Select a script on the left panel
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#each allItems($app.grid, $app.subgrids) as gridItem (gridItem.data.id)}
|
||||
{#each $app.grid as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={gridItem.data.id}
|
||||
@@ -44,6 +45,31 @@
|
||||
{/each}
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#if $app.subgrids}
|
||||
{#each Object.keys($app.subgrids ?? {}) as key (key)}
|
||||
{#each $app.subgrids[key] as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={gridItem.data.id}
|
||||
bind:componentInput={gridItem.data.componentInput}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if gridItem.data.type === 'tablecomponent'}
|
||||
{#each gridItem.data.actionButtons as actionButton, index (index)}
|
||||
{#if actionButton.id === selectedScriptComponentId}
|
||||
<InlineScriptEditorPanel
|
||||
id={actionButton.id}
|
||||
bind:componentInput={actionButton.componentInput}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
{#each $app.unusedInlineScripts as unusedInlineScript, index (index)}
|
||||
{#if `unused-${index}` === selectedScriptComponentId}
|
||||
<InlineScriptEditor
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: runnables = getAppScripts($lazyGrid)
|
||||
$: runnables = getAppScripts($lazyGrid, $app.subgrids)
|
||||
|
||||
// When selected component changes, update selectedScriptComponentId
|
||||
$: if ($selectedComponent != selectedScriptComponentId) {
|
||||
@@ -53,7 +53,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mb-0 pb-0 pl-2 sticky top-0 bg-white border-b text-xs font-semibold">Runnables</div>
|
||||
<div
|
||||
class="sticky top-0 py-0.5 px-2 text-center bg-gray-200 text-gray-500 text-2xs font-bold tracking-wide border-b border-gray-300"
|
||||
>
|
||||
RUNNABLES
|
||||
</div>
|
||||
<div bind:this={list} class="grow flex flex-col gap-4">
|
||||
<PanelSection title="Inline scripts" smallPadding>
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Schema } from "$lib/common";
|
||||
import type { AppInputs, Runnable } from "../../inputType"
|
||||
import type { GridItem } from "../../types"
|
||||
import { fieldTypeToTsType, schemaToInputsSpec } from "../../utils";
|
||||
import type { AppComponent } from "../component";
|
||||
import type { Schema } from '$lib/common'
|
||||
import type { AppInputs, Runnable } from '../../inputType'
|
||||
import type { GridItem } from '../../types'
|
||||
import { fieldTypeToTsType, schemaToInputsSpec } from '../../utils'
|
||||
import type { AppComponent } from '../component'
|
||||
|
||||
export interface AppScriptsList {
|
||||
inline: { name: string; id: string }[],
|
||||
inline: { name: string; id: string }[]
|
||||
imported: { name: string; id: string }[]
|
||||
}
|
||||
|
||||
@@ -42,38 +42,50 @@ export function computeFields(schema: Schema, defaultUserInput: boolean, fields:
|
||||
return result
|
||||
}
|
||||
|
||||
export function getAppScripts(grid: GridItem[]) {
|
||||
return grid.reduce((acc, gridComponent) => {
|
||||
const component: AppComponent = gridComponent.data
|
||||
const componentInput = component.componentInput
|
||||
function processGridItemRunnable(gridItem: GridItem, list: AppScriptsList): AppScriptsList {
|
||||
const component: AppComponent = gridItem.data
|
||||
const componentInput = component.componentInput
|
||||
if (component.type === 'tablecomponent') {
|
||||
component.actionButtons.forEach((actionButton) => {
|
||||
if (actionButton.componentInput?.type !== 'runnable') {
|
||||
return
|
||||
}
|
||||
processRunnable(actionButton.componentInput.runnable, actionButton.id, list)
|
||||
})
|
||||
}
|
||||
if (componentInput?.type === 'runnable') {
|
||||
processRunnable(componentInput.runnable, gridItem.id, list)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
if (component.type === 'tablecomponent') {
|
||||
component.actionButtons.forEach((actionButton) => {
|
||||
if (actionButton.componentInput?.type !== 'runnable') { return }
|
||||
processRunnable(
|
||||
actionButton.componentInput.runnable,
|
||||
actionButton.id,
|
||||
acc
|
||||
)
|
||||
export function getAppScripts(
|
||||
lazyGrid: GridItem[],
|
||||
subgrids: Record<string, GridItem[]> | undefined
|
||||
): AppScriptsList {
|
||||
const scriptsList = lazyGrid.reduce(
|
||||
(acc, gridComponent) => processGridItemRunnable(gridComponent, acc),
|
||||
{ inline: [], imported: [] } as AppScriptsList
|
||||
)
|
||||
|
||||
if (subgrids) {
|
||||
Object.values(subgrids).forEach((subgrid: GridItem[]) => {
|
||||
subgrid.forEach((subgridComponent: GridItem) => {
|
||||
processGridItemRunnable(subgridComponent, scriptsList)
|
||||
})
|
||||
}
|
||||
if (componentInput?.type === 'runnable') {
|
||||
processRunnable(
|
||||
componentInput.runnable,
|
||||
gridComponent.id,
|
||||
acc
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return acc
|
||||
}, { inline: [], imported: [] } as AppScriptsList)
|
||||
return scriptsList
|
||||
}
|
||||
|
||||
function processRunnable(runnable: Runnable, id: string, list: AppScriptsList) {
|
||||
if (runnable?.type === undefined) { return }
|
||||
if (runnable?.type === undefined) {
|
||||
return
|
||||
}
|
||||
const type: keyof AppScriptsList = runnable.type === 'runnableByPath' ? 'imported' : 'inline'
|
||||
list[type].push({
|
||||
name: runnable[runnable.type === 'runnableByPath' ? 'path' : 'name'],
|
||||
id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
import GridTab from './GridTab.svelte'
|
||||
import { duplicateGridItem } from '../appUtils'
|
||||
import { deleteGridItem } from '../appUtils'
|
||||
import MoveToOtherGrid from './MoveToOtherGrid.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let rowColumns = false
|
||||
@@ -30,12 +31,19 @@
|
||||
export let parent: string | undefined
|
||||
export let noGrid = false
|
||||
|
||||
const { app, staticOutputs, runnableComponents, selectedComponent, worldStore, focusedGrid } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
const {
|
||||
app,
|
||||
staticOutputs,
|
||||
runnableComponents,
|
||||
selectedComponent,
|
||||
worldStore,
|
||||
focusedGrid,
|
||||
stateId
|
||||
} = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function duplicateElement(id: string) {
|
||||
$dirtyStore = true
|
||||
const newId = duplicateGridItem($app, $focusedGrid, id)
|
||||
const newId = duplicateGridItem($app, parent, id)
|
||||
$selectedComponent = newId
|
||||
}
|
||||
|
||||
@@ -43,8 +51,8 @@
|
||||
$selectedComponent = undefined
|
||||
$focusedGrid = undefined
|
||||
if (component && !noGrid) {
|
||||
let ids = deleteGridItem($app, component, parent)
|
||||
for (const key in ids) {
|
||||
let ids = deleteGridItem($app, component, parent, false)
|
||||
for (const key of ids) {
|
||||
delete $staticOutputs[key]
|
||||
delete $runnableComponents[key]
|
||||
}
|
||||
@@ -109,31 +117,35 @@
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{#if component.componentInput?.type === 'runnable' && Object.keys(component.componentInput.fields ?? {}).length > 0}
|
||||
<div class="border w-full">
|
||||
<PanelSection
|
||||
smallPadding
|
||||
title={`Runnable Inputs (${
|
||||
Object.keys(component.componentInput.fields ?? {}).length
|
||||
})`}
|
||||
>
|
||||
<svelte:fragment slot="action">
|
||||
<Tooltip>
|
||||
The runnable inputs of a button component are not settable by the user. They must
|
||||
be defined statically or connected.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
{#key $stateId}
|
||||
{#if component.componentInput?.type === 'runnable'}
|
||||
{#if Object.keys(component.componentInput.fields ?? {}).length > 0}
|
||||
<div class="border w-full">
|
||||
<PanelSection
|
||||
smallPadding
|
||||
title={`Runnable Inputs (${
|
||||
Object.keys(component.componentInput.fields ?? {}).length
|
||||
})`}
|
||||
>
|
||||
<svelte:fragment slot="action">
|
||||
<Tooltip>
|
||||
The runnable inputs of a button component are not settable by the user. They
|
||||
must be defined statically or connected.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
|
||||
<InputsSpecsEditor
|
||||
id={component.id}
|
||||
shouldCapitalize={false}
|
||||
bind:inputSpecs={component.componentInput.fields}
|
||||
userInputEnabled={component.type !== 'buttoncomponent'}
|
||||
{rowColumns}
|
||||
/>
|
||||
</PanelSection>
|
||||
</div>
|
||||
{/if}
|
||||
<InputsSpecsEditor
|
||||
id={component.id}
|
||||
shouldCapitalize={false}
|
||||
bind:inputSpecs={component.componentInput.fields}
|
||||
userInputEnabled={component.type !== 'buttoncomponent'}
|
||||
{rowColumns}
|
||||
/>
|
||||
</PanelSection>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/key}
|
||||
</PanelSection>
|
||||
{/if}
|
||||
|
||||
@@ -165,7 +177,7 @@
|
||||
<PanelSection title="Custom CSS">
|
||||
{#each Object.keys(component.customCss ?? {}) as name}
|
||||
{#if component?.customCss?.[name]}
|
||||
<div class="mb-2">
|
||||
<div class="w-full mb-2">
|
||||
<CssProperty {name} bind:value={component.customCss[name]} />
|
||||
</div>
|
||||
{/if}
|
||||
@@ -176,8 +188,7 @@
|
||||
<PanelSection title="Duplicate">
|
||||
<Button
|
||||
size="xs"
|
||||
color="blue"
|
||||
variant="border"
|
||||
color="dark"
|
||||
startIcon={{ icon: faCopy }}
|
||||
on:click={() => {
|
||||
if (component) {
|
||||
@@ -189,6 +200,10 @@
|
||||
</Button>
|
||||
</PanelSection>
|
||||
|
||||
<PanelSection title="Move to other grid">
|
||||
<MoveToOtherGrid bind:component {parent} />
|
||||
</PanelSection>
|
||||
|
||||
<PanelSection title="Danger zone">
|
||||
<Button
|
||||
size="xs"
|
||||
|
||||
@@ -26,17 +26,24 @@
|
||||
}
|
||||
|
||||
function deleteSubgrid(index: number) {
|
||||
tabs.splice(index, 1)
|
||||
tabs = tabs
|
||||
let subgrid = `${component.id}-${index}`
|
||||
for (const item of $app!.subgrids![subgrid]) {
|
||||
const components = deleteGridItem($app, item.data, subgrid)
|
||||
const components = deleteGridItem($app, item.data, subgrid, false)
|
||||
console.log(components)
|
||||
for (const key in components) {
|
||||
delete $staticOutputs[key]
|
||||
delete $runnableComponents[key]
|
||||
}
|
||||
}
|
||||
delete $app!.subgrids![subgrid]
|
||||
$staticOutputs = $staticOutputs
|
||||
$runnableComponents = $runnableComponents
|
||||
for (let i = index; i < tabs.length - 1; i++) {
|
||||
$app!.subgrids![`${component.id}-${i}`] = $app!.subgrids![`${component.id}-${i + 1}`]
|
||||
}
|
||||
tabs.splice(index, 1)
|
||||
tabs = tabs
|
||||
component.numberOfSubgrids = tabs.length
|
||||
$app = $app
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
|
||||
import { faCopy } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import type { App, AppEditorContext } from '../../types'
|
||||
import {
|
||||
createNewGridItem,
|
||||
deleteGridItem,
|
||||
findGridItem,
|
||||
getAllSubgridsAndComponentIds,
|
||||
insertNewGridItem
|
||||
} from '../appUtils'
|
||||
import type { AppComponent } from '../component'
|
||||
|
||||
export let component: AppComponent | undefined
|
||||
export let parent: string | undefined
|
||||
|
||||
let selectedOption: string
|
||||
|
||||
const { app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function listAllSubGrids(app: App) {
|
||||
return app.subgrids ? Object.keys(app.subgrids) : []
|
||||
}
|
||||
|
||||
function findAndDelete(id: string) {
|
||||
const node = findGridItem($app, id)
|
||||
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
|
||||
const data: AppComponent = JSON.parse(JSON.stringify(node.data))
|
||||
const shouldKeepSubGrid = data.numberOfSubgrids ? data.numberOfSubgrids >= 1 : false
|
||||
|
||||
$dirtyStore = true
|
||||
|
||||
deleteGridItem($app, data, parent, shouldKeepSubGrid)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
function insertComponentInSubGrid(
|
||||
data: AppComponent,
|
||||
targetId: string,
|
||||
targetSubGridIndex: number
|
||||
) {
|
||||
const focusedGrid = {
|
||||
parentComponentId: targetId,
|
||||
subGridIndex: targetSubGridIndex
|
||||
}
|
||||
|
||||
insertNewGridItem($app, data, focusedGrid, true)
|
||||
|
||||
$app.grid = [...$app.grid]
|
||||
}
|
||||
|
||||
function insertComponentInMainGrid(data: AppComponent) {
|
||||
const newComponent = createNewGridItem($app.grid, data.id, data)
|
||||
$app.grid = [...$app.grid, newComponent]
|
||||
}
|
||||
|
||||
function onMove(component: AppComponent) {
|
||||
const data = findAndDelete(component.id)
|
||||
|
||||
if (!data) {
|
||||
return
|
||||
}
|
||||
|
||||
if (selectedOption !== 'main-grid') {
|
||||
const [targetId, targetSubGridIndex] = selectedOption.split('-')
|
||||
insertComponentInSubGrid(data, targetId, parseInt(targetSubGridIndex))
|
||||
} else {
|
||||
insertComponentInMainGrid(data)
|
||||
}
|
||||
}
|
||||
|
||||
const defaultOption = {
|
||||
label: 'Main grid',
|
||||
value: 'main-grid',
|
||||
disabled: parent === undefined
|
||||
}
|
||||
|
||||
$: [subgrids] = component ? getAllSubgridsAndComponentIds($app, component) : [[], []]
|
||||
$: availableGrids = listAllSubGrids($app)
|
||||
$: options = availableGrids
|
||||
? [
|
||||
defaultOption,
|
||||
...availableGrids?.map((grid) => ({
|
||||
label: grid,
|
||||
value: grid,
|
||||
disabled: grid === parent || subgrids.includes(grid)
|
||||
}))
|
||||
]
|
||||
: [defaultOption]
|
||||
</script>
|
||||
|
||||
{#if component && !options.every((option) => option.disabled)}
|
||||
<select bind:value={selectedOption} class="w-full">
|
||||
{#each options as option}
|
||||
<option value={option.value} disabled={option.disabled}>{option.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<Button
|
||||
size="xs"
|
||||
color="dark"
|
||||
startIcon={{ icon: faCopy }}
|
||||
on:click={() => {
|
||||
if (component) {
|
||||
onMove(component)
|
||||
}
|
||||
}}
|
||||
>
|
||||
Move component: {component.id}
|
||||
</Button>
|
||||
{:else}
|
||||
<p class="text-gray-500 text-sm">No grids available</p>
|
||||
{/if}
|
||||
@@ -30,8 +30,8 @@ export interface GeneralAppInput {
|
||||
}
|
||||
|
||||
export type ComponentCssProperty = {
|
||||
class: string
|
||||
style: string
|
||||
class?: string
|
||||
style?: string
|
||||
}
|
||||
|
||||
export type ComponentCustomCSS<T extends string = string> = Record<T, ComponentCssProperty>
|
||||
@@ -42,14 +42,14 @@ export interface BaseAppComponent extends Partial<Aligned> {
|
||||
configuration: Record<
|
||||
string,
|
||||
GeneralAppInput &
|
||||
(
|
||||
| StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
)
|
||||
(
|
||||
| StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
)
|
||||
>
|
||||
card: boolean | undefined
|
||||
customCss?: ComponentCustomCSS
|
||||
@@ -131,6 +131,7 @@ export type AppEditorContext = {
|
||||
errorByComponent: Writable<Record<string, { error: string; componentId: string }>>
|
||||
openDebugRun: Writable<((componentID: string) => void) | undefined>
|
||||
focusedGrid: Writable<FocusedGrid | undefined>
|
||||
stateId: Writable<number>
|
||||
}
|
||||
|
||||
export type FocusedGrid = { parentComponentId: string; subGridIndex: number }
|
||||
|
||||
@@ -3,63 +3,37 @@ import { FlowService, ScriptService } from '$lib/gen'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import type { AppComponent } from './editor/component'
|
||||
|
||||
import type { App, ComponentCssProperty, ComponentCustomCSS, GridItem } from './types'
|
||||
import { getRecommendedDimensionsByComponent } from './editor/component'
|
||||
import { gridColumns } from './gridUtils'
|
||||
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppInput, InputType, ResultAppInput, StaticAppInput } from './inputType'
|
||||
import type { Output } from './rx'
|
||||
import type { App, GridItem } from './types'
|
||||
import { getNextId } from '../flows/flowStateUtils'
|
||||
|
||||
/*
|
||||
export function deleteComponent(
|
||||
subgrid: string | undefined,
|
||||
component: AppComponent,
|
||||
app: App,
|
||||
staticOutputs: Record<string, any>,
|
||||
runnableComponents: Record<string, any>
|
||||
) {
|
||||
if (parentItems) {
|
||||
let index = parentItems.findIndex((item) => item.data?.id === component.id)
|
||||
if (index != -1) {
|
||||
parentItems.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
delete staticOutputs[component.id]
|
||||
delete runnableComponents[component.id]
|
||||
|
||||
if (
|
||||
component.componentInput?.type === 'runnable' &&
|
||||
component.componentInput?.runnable?.type === 'runnableByName'
|
||||
) {
|
||||
const { name, inlineScript } = component.componentInput.runnable
|
||||
|
||||
if (inlineScript) {
|
||||
if (!app.unusedInlineScripts) {
|
||||
app.unusedInlineScripts = []
|
||||
}
|
||||
|
||||
app.unusedInlineScripts.push({
|
||||
name,
|
||||
inlineScript
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
export function allItems(grid: GridItem[], subgrids: Record<string, GridItem[]> | undefined): GridItem[] {
|
||||
export function allItems(
|
||||
grid: GridItem[],
|
||||
subgrids: Record<string, GridItem[]> | undefined
|
||||
): GridItem[] {
|
||||
if (subgrids == undefined) {
|
||||
return grid
|
||||
}
|
||||
return [...grid, ...Object.values(subgrids).flat()]
|
||||
}
|
||||
|
||||
export function allItemsWithParent(grid: GridItem[], subgrids: Record<string, GridItem[]> | undefined): [GridItem, string | undefined][] {
|
||||
export function allItemsWithParent(
|
||||
grid: GridItem[],
|
||||
subgrids: Record<string, GridItem[]> | undefined
|
||||
): [GridItem, string | undefined][] {
|
||||
const items: [GridItem, string | undefined][] = grid.map((item) => [item, undefined])
|
||||
if (subgrids == undefined) {
|
||||
return items
|
||||
}
|
||||
return [...items, ...Object.entries(subgrids).flatMap(([k, v]) => v.map((g) => [g, k] as [GridItem, string]))]
|
||||
return [
|
||||
...items,
|
||||
...Object.entries(subgrids).flatMap(([k, v]) => v.map((g) => [g, k] as [GridItem, string]))
|
||||
]
|
||||
}
|
||||
|
||||
export async function loadSchema(
|
||||
@@ -264,3 +238,128 @@ export function toPascalCase(text: string) {
|
||||
export function toKebabCase(text: string) {
|
||||
return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
||||
}
|
||||
|
||||
export function findParent(root: GridItem[], id: string): GridItem | undefined {
|
||||
for (const a of root) {
|
||||
if (a.id === id) {
|
||||
return a
|
||||
}
|
||||
|
||||
if (a.data.subGrids) {
|
||||
// Recursively search the sub-grids
|
||||
for (const subGrid of a.data.subGrids) {
|
||||
const result = findParent(subGrid, id)
|
||||
if (result) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function insertNewGridItem(
|
||||
root: GridItem[],
|
||||
id: string,
|
||||
subGridIndex: number,
|
||||
newId: string,
|
||||
data: AppComponent
|
||||
): GridItem[] {
|
||||
const parentA = findParent(root, id)
|
||||
|
||||
if (!parentA) {
|
||||
throw new Error(`Parent A object with ID ${id} not found.`)
|
||||
}
|
||||
|
||||
const subGrid = parentA.data.subGrids[subGridIndex]
|
||||
|
||||
if (!subGrid) {
|
||||
throw new Error(`Sub-grid with index ${subGridIndex} not found.`)
|
||||
}
|
||||
|
||||
const newItem = createNewGridItem(subGrid ?? [], newId, data)
|
||||
subGrid.push(newItem)
|
||||
return root
|
||||
}
|
||||
|
||||
// The grid is needed to find a space for the new component
|
||||
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
|
||||
const appComponent = data
|
||||
|
||||
appComponent.id = id
|
||||
|
||||
const newComponent = {
|
||||
fixed: false,
|
||||
resizable: true,
|
||||
draggable: true,
|
||||
customDragger: false,
|
||||
customResizer: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
|
||||
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
|
||||
|
||||
const newItem: GridItem = {
|
||||
data: newData,
|
||||
id: id
|
||||
}
|
||||
|
||||
gridColumns.forEach((column) => {
|
||||
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
|
||||
|
||||
newItem[column] = {
|
||||
...newComponent,
|
||||
min: { w: 1, h: 1 },
|
||||
max: { w: column, h: 100 },
|
||||
w: rec.w,
|
||||
h: rec.h
|
||||
}
|
||||
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
|
||||
newItem[column] = { ...newItem[column], ...position }
|
||||
})
|
||||
|
||||
return newItem
|
||||
}
|
||||
|
||||
function recursiveGetIds(gridItem: GridItem): string[] {
|
||||
const subGrids = gridItem.data.subGrids ?? []
|
||||
const subGridIds = subGrids
|
||||
.map((subGrid: GridItem[]) => subGrid.map(recursiveGetIds))
|
||||
.flat(Infinity)
|
||||
return [gridItem.data.id, ...subGridIds]
|
||||
}
|
||||
|
||||
export function getNextGridItemId(grid: GridItem[] = []): string {
|
||||
const gridItemIds = grid.map(recursiveGetIds).flat()
|
||||
const id = getNextId(gridItemIds)
|
||||
return id
|
||||
}
|
||||
|
||||
export function concatCustomCss<T extends string = string>(
|
||||
appCss?: ComponentCustomCSS<T>,
|
||||
componentCss?: ComponentCustomCSS<T>
|
||||
): Record<T, ComponentCssProperty> | undefined {
|
||||
if (!componentCss) return undefined
|
||||
|
||||
const customStyle = {} as Record<T, ComponentCssProperty>
|
||||
Object.keys(componentCss).forEach((key) => {
|
||||
const k = key as keyof typeof componentCss
|
||||
|
||||
// This is the general style of the component type
|
||||
const appStyle = appCss?.[k]?.style?.trim() || ''
|
||||
const appEnding = appStyle?.endsWith(';') || !appStyle ? ' ' : '; '
|
||||
|
||||
// This is the custom style of the component instance
|
||||
const compStyle = componentCss[k]?.style?.trim() || ''
|
||||
const compEnding = compStyle?.endsWith(';') || !compStyle ? ' ' : ';'
|
||||
|
||||
customStyle[k] = {
|
||||
style: (appStyle + appEnding + compStyle + compEnding).trim(),
|
||||
class: twMerge(appCss?.[k]?.class, componentCss[k]?.class)
|
||||
}
|
||||
})
|
||||
|
||||
return customStyle
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
// Order of classes: border, border modifier, bg, bg modifier, text, text modifier, everything else
|
||||
const colorVariants: Record<ButtonType.Color, Record<ButtonType.Variant, string>> = {
|
||||
none: {
|
||||
border: '',
|
||||
contained: ''
|
||||
},
|
||||
|
||||
blue: {
|
||||
border:
|
||||
'border-frost-500 hover:border-frost-700 focus:border-frost-700 bg-white hover:bg-frost-100 focus:bg-frost-100 text-frost-500 hover:text-frost-700 focus:text-frost-700 focus:ring-frost-300',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const BUTTON_COLORS = ['blue', 'red', 'dark', 'light', 'green', 'gray'] as const
|
||||
export const BUTTON_COLORS = ['blue', 'red', 'dark', 'light', 'green', 'gray', 'none'] as const
|
||||
|
||||
export namespace ButtonType {
|
||||
|
||||
|
||||
@@ -76,9 +76,15 @@
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<aside class="drawer {$$props.class}" class:open class:close={!open && timeout} {style}>
|
||||
<div class="overlay" on:click={handleClickAway} />
|
||||
<div class="panel {placement}" class:size>
|
||||
<aside
|
||||
class="drawer {$$props.class} {$$props.positionClass}"
|
||||
class:open
|
||||
class:close={!open && timeout}
|
||||
{style}
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="overlay {$$props.positionClass}" on:click={handleClickAway} />
|
||||
<div class="panel {placement} {$$props.positionClass}" class:size>
|
||||
{#if open || !timeout || alwaysOpen}
|
||||
<slot />
|
||||
{/if}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { faClose } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import Button from '../button/Button.svelte'
|
||||
|
||||
export let title: string | undefined = undefined
|
||||
export let overflow_y = true
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user