Compare commits

..

99 Commits

Author SHA1 Message Date
Ruben Fiszel
1ea08f1e8f inline script drawer 2023-02-28 15:46:06 +01:00
Ruben Fiszel
d302c92766 Merge branch 'main' into rf/flowFix 2023-02-28 11:18:22 +01:00
Ruben Fiszel
ea2ebfa92e fix compile issue 2023-02-28 11:18:09 +01:00
Ruben Fiszel
128622117d progress 2023-02-28 11:15:56 +01:00
dependabot[bot]
ba856be10d chore(deps): bump docker/metadata-action from 3 to 4 (#1243)
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 3 to 4.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-28 11:02:14 +01:00
dependabot[bot]
333b873ee9 chore(deps): bump docker/build-push-action from 3 to 4 (#1186)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-28 11:02:00 +01:00
dependabot[bot]
2785b05064 chore(deps-dev): bump @playwright/test in /frontend (#1244)
Bumps [@playwright/test](https://github.com/Microsoft/playwright) from 1.29.2 to 1.31.1.
- [Release notes](https://github.com/Microsoft/playwright/releases)
- [Commits](https://github.com/Microsoft/playwright/compare/v1.29.2...v1.31.1)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-28 11:01:33 +01:00
Faton Ramadani
a67f10eeb6 fix(frontend): Fix deeply nested move (#1245)
* fix(frontend): Fix deeply nested move

* fix(frontend): update comment
2023-02-28 10:53:51 +01:00
Ruben Fiszel
287b2db22f feat(cli): add autocompletions 2023-02-28 10:32:34 +01:00
Ádám Kovács
a4e4d188ad fix(frontend): Add more app custom css (#1229)
* fix(frontend): Add container custom css

* fix(frontend): Add form custom css

* fix(frontend): Add form button custom css

* feat(frontend): Add css quick reset button

* feat(frontend): Filter component css by usage

* fix(frontend): Save state of unused component display

* fix(frontend): Add pie chart custom css

* fix(frontend): Add bar chart custom css

* fix(frontend): Update vega lite and plotly loading

* fix(frontend): Add html and timeseries custom css

* fix(frontend): Add scatter chart custom css

* fix(frontend): Add table custom css

* fix(frontend): Revert container custom styles

* fix(frontend): Add toggle custom css

* fix(frontend): Add text input custom css

* fix(frontend): Update

* fix(frontend): Remove undefined css customizations
2023-02-28 09:21:56 +01:00
Ruben Fiszel
150ce7f731 Merge branch 'main' into rf/flowFix 2023-02-27 18:54:26 +01:00
Ruben Fiszel
2244e83b9d fix(frontend): invisible subgrids have h-0 + app policies fix 2023-02-27 18:38:22 +01:00
Ruben Fiszel
fae406ee8f update docs 2023-02-27 18:26:59 +01:00
Ruben Fiszel
42d1cd6456 fix(frontend): display currently selected filter even if not in list 2023-02-27 16:20:31 +01:00
Ruben Fiszel
4b64e75bd1 add back all tailwind colors to tailwind config 2023-02-27 15:11:23 +01:00
Ruben Fiszel
51a7eaaeb0 rename counters 2023-02-27 14:52:24 +01:00
Ruben Fiszel
8589b70ccf apps improvements 2023-02-27 14:37:32 +01:00
Ruben Fiszel
0bf6f23c9e fix setup app to use updated version of the CLI 2023-02-27 14:16:57 +01:00
Ruben Fiszel
e56869092a feat(backend): use counter for sleep/execution/pull durations 2023-02-27 12:00:32 +01:00
Ruben Fiszel
6b8758f4a5 chore(main): release 1.70.1 (#1241) 2023-02-27 10:30:41 +01:00
Ruben Fiszel
fbc929ba1b chore(main): release 1.70.1 (#1239)
* chore(main): release 1.70.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-27 10:07:26 +01:00
Faton Ramadani
97602ac6db fix(frontend): Fix inline scripts list (#1240) 2023-02-27 10:06:42 +01:00
Faton Ramadani
8ee9d67f4f fix(frontend): Fix subgrid lock (#1232)
* fix(frontend): Fix subgrid lock

* feat(frontend): restore
2023-02-27 10:00:18 +01:00
Ruben Fiszel
4bf6e753f1 fix findGridItemById 2023-02-27 09:56:17 +01:00
Faton Ramadani
70eab303bd fix(frontend): Disable move in nested subgrid (#1238)
* fix(frontend): Disable move in nested subgrid

* fix(frontend): Disable move in nested subgrid
2023-02-27 09:50:39 +01:00
Ruben Fiszel
c051ffeb42 fix(cli): make cli resilient to systems without openable browsers 2023-02-27 09:48:52 +01:00
Ruben Fiszel
ebb68e5320 chore(main): release 1.70.0 (#1236)
* chore(main): release 1.70.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-27 09:25:03 +01:00
Ruben Fiszel
04a076f1db fix(cli): bump cli to non broken client 1.69.3 2023-02-27 09:24:18 +01:00
Ruben Fiszel
ebd2e0323e fix stripe checkout 2023-02-27 08:49:36 +01:00
Ruben Fiszel
cd25570003 fix minor editor bugs 2023-02-27 00:53:49 +01:00
Ruben Fiszel
e95f8ef6bf add none color for buttons 2023-02-27 00:27:20 +01:00
Ruben Fiszel
c3d1c8ac39 fix many apps bugs 2023-02-26 23:43:00 +01:00
Ruben Fiszel
d38aff2fe2 fix: app setup and sync now uses 1.69.3 2023-02-26 14:09:16 +01:00
Ruben Fiszel
95851ea486 minor app nits 2023-02-26 13:58:51 +01:00
Ruben Fiszel
b690d801d4 feat(apps): add ag grid 2023-02-25 13:11:50 +01:00
Faton Ramadani
104e4ac5e7 feat(frontend): move to other grid (#1230)
* feat(frontend): move to other grid

* feat(frontend): wip

* feat(frontend): Fix component move

* fix(frontend): Fix build

* feat(frontend): Fix moving

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

* Apply automatic changes

---------

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

* Apply automatic changes

---------

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

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-23 18:07:56 +01:00
Ruben Fiszel
d543650b31 fix(cli): .wmillignore whitelist behavior 2023-02-23 18:02:42 +01:00
Faton Ramadani
089a6b6ae5 feat(frontend): Duplicate component (#1228)
* feat(frontend): Duplicate component

* feat(frontend): add missing types
2023-02-23 17:43:27 +01:00
Faton Ramadani
857ee5f318 feat(frontend): Properly delete tab content (#1227) 2023-02-23 16:02:15 +01:00
Faton Ramadani
6ad876ebb4 feat(frontend): Support deeply nested components (#1225) 2023-02-23 15:33:14 +01:00
Ádám Kovács
ab4137640e refactor(frontend): Reorganise app components (#1224)
* refactor(frontend): Reorganise app components

* refactor(frontend): Restructure app component
2023-02-23 14:15:45 +01:00
Ruben Fiszel
2bd8fabcf7 chore(main): release 1.68.0 (#1223)
* chore(main): release 1.68.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-23 13:42:42 +01:00
Ruben Fiszel
3b7160e84a fix(cli): better ergonomics around workspaces 2023-02-23 13:31:08 +01:00
Ruben Fiszel
40c12e6139 fix(cli): better ergonomics around workspace add 2023-02-23 13:19:14 +01:00
Ádám Kovács
6044e3b6ef feat(frontend): Add more app component CSS customisation (#1218)
* fix(frontend): Update app style editor

* fix(frontend): Update component custom css typings

* fix(frontend): Generalise custom CSS inputs

* feat(frontend): Add display CSS customization
2023-02-23 11:42:32 +01:00
Ruben Fiszel
18ff5c7cef chore(main): release 1.67.4 (#1222)
* chore(main): release 1.67.4

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-23 09:06:34 +01:00
Ruben Fiszel
e54dc3ff97 fix(backend): workflow check for has_failure_module 2023-02-23 09:01:02 +01:00
Ruben Fiszel
4d5aae69c8 chore(main): release 1.67.3 (#1221)
* chore(main): release 1.67.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-23 08:34:22 +01:00
Ruben Fiszel
ec57c5977f fix(cli): ignone non wmill looking files 2023-02-23 08:26:22 +01:00
Ruben Fiszel
df1b724626 do not create default variables on workspace creation 2023-02-23 08:07:35 +01:00
Ruben Fiszel
268dfbf831 chore(main): release 1.67.2 (#1220)
* chore(main): release 1.67.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-23 08:00:15 +01:00
Ruben Fiszel
969e89f8bb fix(cli): ignone non wmill looking files 2023-02-23 07:40:04 +01:00
Ruben Fiszel
5997503961 chore(main): release 1.67.1 (#1219) 2023-02-22 23:47:37 +01:00
Ruben Fiszel
3fa24adad0 fix(cli): coloring nits 2023-02-22 23:46:08 +01:00
Ruben Fiszel
7471be1d81 update rustpython parser 2023-02-22 23:43:06 +01:00
Ruben Fiszel
d64e1c116a nits on cli output 2023-02-22 23:28:50 +01:00
Ruben Fiszel
9267b1fb90 nits on webhook sync 2023-02-22 22:44:19 +01:00
Ruben Fiszel
6528a68668 chore(main): release 1.67.0 (#1216)
* chore(main): release 1.67.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2023-02-22 22:39:14 +01:00
Ruben Fiszel
4fd4d17a0d update README 2023-02-22 21:49:13 +01:00
Ruben Fiszel
0548803ab7 fix flow rendering 2023-02-22 21:27:58 +01:00
Ruben Fiszel
0085b46c1e fix(cli): add --fail-conflicts to ci push 2023-02-22 21:00:48 +01:00
Kai Jellinghaus
81ffd49bef Remove Stripe (#1217) 2023-02-22 19:15:10 +01:00
Faton Ramadani
dbc59e9521 feat(frontend): Add app sub grids (#1208)
* feat(frontend): Add app sub grids

* feat(frontend): remove temp file

* feat(frontend): update package.json

* feat(frontend): fix build

* fixes

* feat(frontend): wip

* feat(frontend): wip

* feat(frontend): update dependencies

* feat(frontend): update dependencies

* feat(frontend): fix scrolling issues

* feat(frontend): fix preview + delete

* feat(frontend): done

* feat(frontend): remove dead code

* feat(frontend): fix selection

* feat(frontend): add container

* feat(frontend): fix package.json

* feat(frontend): fix package.json

* feat(frontend): fix package.json

* feat(frontend): fix package.json

* feat(frontend): fix package.json

* feat(frontend): restore npm package

* feat(frontend): add missing dependencies

* feat(frontend): remove missing dependencies

* feat(frontend): fix package.json

* feat(frontend): fix package.json

* feat(frontend): fix package.json

* feat(frontend): revert

* feat(frontend): fix package-lock

* feat(frontend): fix package-lock

* fix package-lock.json

* update

---------

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2023-02-22 17:52:10 +01:00
174 changed files with 6911 additions and 2668 deletions

View File

@@ -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: .

View File

@@ -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

View File

@@ -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: ./

View File

@@ -1,6 +1,140 @@
# Changelog
## [1.70.1](https://github.com/windmill-labs/windmill/compare/v1.70.0...v1.70.1) (2023-02-27)
### Bug Fixes
* **cli:** make cli resilient to systems without openable browsers ([c051ffe](https://github.com/windmill-labs/windmill/commit/c051ffeb42c1cff609f93da7745036ea722e17d4))
* **frontend:** Disable move in nested subgrid ([#1238](https://github.com/windmill-labs/windmill/issues/1238)) ([70eab30](https://github.com/windmill-labs/windmill/commit/70eab303bd45111ae198d9b710bfd6f9f59e53b0))
* **frontend:** Fix inline scripts list ([#1240](https://github.com/windmill-labs/windmill/issues/1240)) ([97602ac](https://github.com/windmill-labs/windmill/commit/97602ac6db1404d36d160a431ffcea6c0f567a48))
* **frontend:** Fix subgrid lock ([#1232](https://github.com/windmill-labs/windmill/issues/1232)) ([8ee9d67](https://github.com/windmill-labs/windmill/commit/8ee9d67f4faa91446338b41c664ef91913eb8b81))
## [1.70.1](https://github.com/windmill-labs/windmill/compare/v1.70.0...v1.70.1) (2023-02-27)
### Bug Fixes
* **cli:** make cli resilient to systems without openable browsers ([c051ffe](https://github.com/windmill-labs/windmill/commit/c051ffeb42c1cff609f93da7745036ea722e17d4))
* **frontend:** Disable move in nested subgrid ([#1238](https://github.com/windmill-labs/windmill/issues/1238)) ([70eab30](https://github.com/windmill-labs/windmill/commit/70eab303bd45111ae198d9b710bfd6f9f59e53b0))
* **frontend:** Fix subgrid lock ([#1232](https://github.com/windmill-labs/windmill/issues/1232)) ([8ee9d67](https://github.com/windmill-labs/windmill/commit/8ee9d67f4faa91446338b41c664ef91913eb8b81))
## [1.70.0](https://github.com/windmill-labs/windmill/compare/v1.69.3...v1.70.0) (2023-02-27)
### Features
* **apps:** add ag grid ([b690d80](https://github.com/windmill-labs/windmill/commit/b690d801d4aa5695ee558e81d1ed114074dfcb83))
* **frontend:** move to other grid ([#1230](https://github.com/windmill-labs/windmill/issues/1230)) ([104e4ac](https://github.com/windmill-labs/windmill/commit/104e4ac5e790c30e6fb6b27726776693038d4f19))
### Bug Fixes
* app setup and sync now uses 1.69.3 ([d38aff2](https://github.com/windmill-labs/windmill/commit/d38aff2fe228f23eb18c3991392928c064e6aca2))
* **frontend:** Fix duplication ([#1237](https://github.com/windmill-labs/windmill/issues/1237)) ([e87f4fc](https://github.com/windmill-labs/windmill/commit/e87f4fc44b847a573f5acafc0348fbcbfcb2258f))
* **frontend:** fix graph viewer id assignment ([e1f686d](https://github.com/windmill-labs/windmill/commit/e1f686d8508cfc1f73c43be08facc44217ca8de0))
## [1.69.3](https://github.com/windmill-labs/windmill/compare/v1.69.2...v1.69.3) (2023-02-24)
### Bug Fixes
* **deno:** fix denoify buffer handling ([c2e5afd](https://github.com/windmill-labs/windmill/commit/c2e5afd4e07fb63375832f308da8c744616ee188))
## [1.69.2](https://github.com/windmill-labs/windmill/compare/v1.69.1...v1.69.2) (2023-02-24)
### Bug Fixes
* **app:** fix all nested behavior ([dd28308](https://github.com/windmill-labs/windmill/commit/dd28308c3cf1877ba3f19dcd2bd20bf1c7896a99))
* **frontend:** delete grid item ([008c30f](https://github.com/windmill-labs/windmill/commit/008c30fcaad64af512407f9889a9881fafac0868))
* **frontend:** duplicate ([483407c](https://github.com/windmill-labs/windmill/commit/483407cdf0e1ed61de180a904934e950fed4adc3))
* **frontend:** Fix findGridItem ([a8295d0](https://github.com/windmill-labs/windmill/commit/a8295d0b5acd08cec42b7939d907df5c25132644))
* **frontend:** Fix findGridItem ([5bb77ed](https://github.com/windmill-labs/windmill/commit/5bb77edf45740a75e969b1bef31580271c9d5505))
* **frontend:** Fix next id ([8ddcf4d](https://github.com/windmill-labs/windmill/commit/8ddcf4d9c1a8d6dd20ee241a3f308811c49e58f1))
* **frontend:** gridtab ([fa105b4](https://github.com/windmill-labs/windmill/commit/fa105b4caeaa2d0e9704a48f6caf8d846839c23e))
* **frontend:** rewrote utils ([ea1b2c2](https://github.com/windmill-labs/windmill/commit/ea1b2c29b95282df347ef9c5973917fa3880e843))
* **frontend:** wip ([33ebe2d](https://github.com/windmill-labs/windmill/commit/33ebe2da8e81476be62a2567d5012573a8a010b6))
## [1.69.1](https://github.com/windmill-labs/windmill/compare/v1.69.0...v1.69.1) (2023-02-24)
### Bug Fixes
* **deno:** remove mysql support waiting for deno fix ([dd7e8c7](https://github.com/windmill-labs/windmill/commit/dd7e8c742c83f6a1d13e4343ca626c0b5efc06fb))
* **deno:** remove mysql support waiting for deno fix ([2f78132](https://github.com/windmill-labs/windmill/commit/2f78132e081bdf3d7468e022f0e981ebfa52cfb3))
* **frontend:** containers and tab fixes v1 ([27cac3f](https://github.com/windmill-labs/windmill/commit/27cac3ffe69c4dac160e9e55ffd1eb8ea348d487))
* **frontend:** containers and tab fixes v1 ([705703a](https://github.com/windmill-labs/windmill/commit/705703a5e2f2dc7ceb4c215221f72bf624799841))
* **frontend:** containers and tab fixes v1 ([fac31c6](https://github.com/windmill-labs/windmill/commit/fac31c6628b289ad6aae92434e312c4be281a4d2))
## [1.69.0](https://github.com/windmill-labs/windmill/compare/v1.68.0...v1.69.0) (2023-02-23)
### Features
* **frontend:** Duplicate component ([#1228](https://github.com/windmill-labs/windmill/issues/1228)) ([089a6b6](https://github.com/windmill-labs/windmill/commit/089a6b6ae52e8d28dd15e2f9a6ad900c5853d0a1))
* **frontend:** Properly delete tab content ([#1227](https://github.com/windmill-labs/windmill/issues/1227)) ([857ee5f](https://github.com/windmill-labs/windmill/commit/857ee5f318466d12bf0d41515451798df087ab74))
* **frontend:** Support deeply nested components ([#1225](https://github.com/windmill-labs/windmill/issues/1225)) ([6ad876e](https://github.com/windmill-labs/windmill/commit/6ad876ebb45a934b7a4dc980cf38a5228d7d11f1))
### Bug Fixes
* **cli:** .wmillignore whitelist behavior ([d543650](https://github.com/windmill-labs/windmill/commit/d543650b313c434e794ad800aefe4aeda83c0fed))
## [1.68.0](https://github.com/windmill-labs/windmill/compare/v1.67.4...v1.68.0) (2023-02-23)
### Features
* **frontend:** Add more app component CSS customisation ([#1218](https://github.com/windmill-labs/windmill/issues/1218)) ([6044e3b](https://github.com/windmill-labs/windmill/commit/6044e3b6ef92e89b8f15f38bc2d0986ec64105d5))
### Bug Fixes
* **cli:** better ergonomics around workspace add ([40c12e6](https://github.com/windmill-labs/windmill/commit/40c12e6139c7b42d7ab169bab2dd37f8b43bea06))
* **cli:** better ergonomics around workspaces ([3b7160e](https://github.com/windmill-labs/windmill/commit/3b7160e84aa454bdb5f343da99cfd97a6b319937))
## [1.67.4](https://github.com/windmill-labs/windmill/compare/v1.67.3...v1.67.4) (2023-02-23)
### Bug Fixes
* **backend:** workflow check for has_failure_module ([e54dc3f](https://github.com/windmill-labs/windmill/commit/e54dc3ff97e4454a15b9efe25cc12f6c9e1e176b))
## [1.67.3](https://github.com/windmill-labs/windmill/compare/v1.67.2...v1.67.3) (2023-02-23)
### Bug Fixes
* **cli:** ignone non wmill looking files ([ec57c59](https://github.com/windmill-labs/windmill/commit/ec57c5977f122b629a07e05bc3551662d518ce30))
## [1.67.2](https://github.com/windmill-labs/windmill/compare/v1.67.1...v1.67.2) (2023-02-23)
### Bug Fixes
* **cli:** ignone non wmill looking files ([969e89f](https://github.com/windmill-labs/windmill/commit/969e89f8bbc10f6712920321b70ede35f19ab9ed))
## [1.67.1](https://github.com/windmill-labs/windmill/compare/v1.67.0...v1.67.1) (2023-02-22)
### Bug Fixes
* **cli:** coloring nits ([3fa24ad](https://github.com/windmill-labs/windmill/commit/3fa24adad0a07ba2f469c545b28251b035efdf90))
## [1.67.0](https://github.com/windmill-labs/windmill/compare/v1.66.1...v1.67.0) (2023-02-22)
### Features
* **frontend:** Add app sub grids ([#1208](https://github.com/windmill-labs/windmill/issues/1208)) ([dbc59e9](https://github.com/windmill-labs/windmill/commit/dbc59e952143ee5813780ad13794cef4e036911c))
### Bug Fixes
* **cli:** add --fail-conflicts to ci push ([0085b46](https://github.com/windmill-labs/windmill/commit/0085b46c1e3b8267fcafcb06ce72b4d820e49df5))
## [1.66.1](https://github.com/windmill-labs/windmill/compare/v1.66.0...v1.66.1) (2023-02-22)

View File

@@ -20,41 +20,23 @@ Open-source developer infrastructure for internal tools. Self-hostable alternati
</a>
</p>
---
<p align="center">
<a href="https://app.windmill.dev">Try it</a> - <a href="https://docs.windmill.dev/docs/intro/">Docs</a> - <a href="https://discord.gg/V7PM2YHsPB">Discord</a> - <a href="https://hub.windmill.dev">Hub</a> - <a href="https://docs.windmill.dev/docs/misc/contributing">Contributor's guide</a>
</p>
**Try it (personal workspaces are free forever)**: <https://app.windmill.dev>
# Windmill - Turn scripts into workflows and UIs that you can share and run at scale
**Documentation**: <https://www.windmill.dev>
**Discord**: <https://discord.gg/V7PM2YHsPB>
**Hub**: <https://hub.windmill.dev>
**Contributor's guide**: <https://docs.windmill.dev/docs/misc/contributing>
**Roadmap**: <https://github.com/orgs/windmill-labs/projects/2>
You can show your support for the project by starring this repo.
Windmill Labs offers commercial licenses, an enterprise edition, local hub
mirrors, and support: contact ruben@windmill.dev.
---
# Windmill
Windmill is <b>fully open-sourced (AGPLv3)</b>
Windmill is <b>fully open-sourced (AGPLv3)</b> and Windmill Labs offers dedicated instance and commercial support and licenses.
![Windmill Diagram](/imgs/stacks.svg)
https://user-images.githubusercontent.com/275584/218350457-bc2fdc3b-e667-4da5-a2bd-3bacc1f0ec79.mp4
- [Windmill](#windmill)
- [Windmill - Turn scripts into workflows and UIs that you can share and run at scale](#windmill---turn-scripts-into-workflows-and-uis-that-you-can-share-and-run-at-scale)
- [Main Concepts](#main-concepts)
- [Show me some actual script code](#show-me-some-actual-script-code)
- [CLI](#cli)
- [Running scripts locally](#running-scripts-locally)
- [Layout](#layout)
- [Stack](#stack)
- [Security](#security)
- [Sandboxing](#sandboxing)
@@ -141,13 +123,6 @@ scripts from local files, github repos and to run scripts and flows on the insta
You can run your script locally easily, you simply need to pass the right environment variables for the `wmill` client library to fetch resource and variables from your instance if necessary. See more: <https://docs.windmill.dev/docs/advanced/local_development/>
## Layout
- `backend/`: Rust backend
- `frontend`: Svelte frontend
- `lsp/`: Lsp asssistant for the monaco editor
- `<lang>-client/`: Windmill client for the given `<lang>`
## Stack
- Postgres as the database
@@ -392,4 +367,4 @@ running options.
## Copyright
Windmill Labs, Inc 2022
Windmill Labs, Inc 2023

116
backend/Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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';

View File

@@ -17,10 +17,8 @@ use serde_json::json;
use windmill_common::error;
use windmill_parser::{json_to_typ, Arg, MainArgSignature, Typ};
use rustpython_parser::{
ast::{Constant, ExprKind, Located, StmtKind},
parser,
};
use rustpython_parser as parser;
use rustpython_parser::ast::{Constant, ExprKind, Located, StmtKind};
const DEF_MAIN: &str = "def main(";
const FUNCTION_CALL: &str = "<function call>";

View File

@@ -9,7 +9,7 @@ name = "windmill_api"
path = "src/lib.rs"
[features]
enterprise = ["windmill-queue/enterprise"]
enterprise = ["windmill-queue/enterprise", "async-stripe"]
[dependencies]
windmill-queue.workspace = true
@@ -65,7 +65,7 @@ hmac.workspace = true
cookie.workspace = true
sha2.workspace = true
urlencoding.workspace = true
async-stripe.workspace = true
async-stripe = { workspace = true, optional = true }
lazy_static.workspace = true
prometheus.workspace = true
async_zip.workspace = true

View File

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

View File

@@ -6,8 +6,11 @@
* LICENSE-AGPL for a copy of the license.
*/
#[cfg(feature = "enterprise")]
use std::str::FromStr;
#[cfg(feature = "enterprise")]
use crate::BASE_URL;
use crate::{
apps::AppWithLastVersion,
db::{UserDB, DB},
@@ -15,16 +18,19 @@ use crate::{
resources::{Resource, ResourceType},
users::{Authed, WorkspaceInvite, NEW_USER_WEBHOOK},
utils::require_super_admin,
BASE_URL, HTTP_CLIENT,
HTTP_CLIENT,
};
#[cfg(feature = "enterprise")]
use axum::response::Redirect;
use axum::{
body::StreamBody,
extract::{Extension, Path, Query},
headers,
response::{IntoResponse, Redirect},
response::IntoResponse,
routing::{delete, get, post},
Json, Router,
};
#[cfg(feature = "enterprise")]
use stripe::CustomerId;
use windmill_audit::{audit_log, ActionKind};
use windmill_common::{
@@ -43,7 +49,7 @@ use tokio::fs::File;
use tokio_util::io::ReaderStream;
pub fn workspaced_service() -> Router {
Router::new()
let router = Router::new()
.route("/list_pending_invites", get(list_pending_invites))
.route("/update", post(edit_workspace))
.route("/archive", post(archive_workspace))
@@ -55,9 +61,17 @@ pub fn workspaced_service() -> Router {
.route("/edit_webhook", post(edit_webhook))
.route("/edit_auto_invite", post(edit_auto_invite))
.route("/tarball", get(tarball_workspace))
.route("/premium_info", get(premium_info))
.route("/premium_info", get(premium_info));
#[cfg(feature = "enterprise")]
tracing::info!("stripe enabled");
#[cfg(feature = "enterprise")]
let router = router
.route("/checkout", get(stripe_checkout))
.route("/billing_portal", get(stripe_portal))
.route("/billing_portal", get(stripe_portal));
router
}
pub fn global_service() -> Router {
Router::new()
@@ -217,11 +231,13 @@ async fn premium_info(
Ok(Json(row))
}
#[cfg(feature = "enterprise")]
#[derive(Deserialize)]
struct PlanQuery {
plan: String,
}
#[cfg(feature = "enterprise")]
async fn stripe_checkout(
authed: Authed,
Path(w_id): Path<String>,
@@ -287,6 +303,7 @@ async fn stripe_checkout(
}
}
#[cfg(feature = "enterprise")]
async fn stripe_portal(
authed: Authed,
Path(w_id): Path<String>,
@@ -660,19 +677,19 @@ async fn create_workspace(
.execute(&mut tx)
.await?;
let mc = magic_crypt::new_magic_crypt!(key, 256);
sqlx::query!(
"INSERT INTO variable
(workspace_id, path, value, is_secret, description)
VALUES ($1, 'g/all/pretty_secret', $2, true, 'This item is secret'),
($3, 'g/all/not_secret', $4, false, 'This item is not secret')",
nw.id,
crate::variables::encrypt(&mc, "pretty secret value"),
nw.id,
"finland does not actually exist",
)
.execute(&mut tx)
.await?;
// let mc = magic_crypt::new_magic_crypt!(key, 256);
// sqlx::query!(
// "INSERT INTO variable
// (workspace_id, path, value, is_secret, description)
// VALUES ($1, 'g/all/pretty_secret', $2, true, 'This item is secret'),
// ($3, 'g/all/not_secret', $4, false, 'This item is not secret')",
// nw.id,
// crate::variables::encrypt(&mc, "pretty secret value"),
// nw.id,
// "finland does not actually exist",
// )
// .execute(&mut tx)
// .await?;
sqlx::query!(
"INSERT INTO usr

View File

@@ -59,6 +59,7 @@ pub struct NewFlow {
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
pub struct FlowValue {
pub modules: Vec<FlowModule>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub failure_module: Option<FlowModule>,
#[serde(default)]
@@ -152,7 +153,9 @@ pub struct FlowModule {
#[serde(alias = "input_transform")]
pub input_transforms: HashMap<String, InputTransform>,
pub value: FlowModuleValue,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_after_if: Option<StopAfterIf>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suspend: Option<Suspend>,
@@ -245,7 +248,9 @@ pub enum FlowModuleValue {
#[serde(alias = "input_transform")]
input_transforms: HashMap<String, InputTransform>,
content: String,
#[serde(skip_serializing_if = "Option::is_none")]
lock: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
path: Option<String>,
language: ScriptLang,
},

View File

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

View File

@@ -383,7 +383,7 @@ lazy_static::lazy_static! {
.unwrap();
static ref WORKER_UPTIME_OPTS: prometheus::Opts = prometheus::opts!(
"worker_uptime",
"Total number of milliseconds since the worker has started"
"Total number of seconds since the worker has started"
);
static ref TIMEOUT: u16 = std::env::var("TIMEOUT")
@@ -445,15 +445,11 @@ pub async fn run_worker(
insert_initial_ping(worker_instance, &worker_name, ip, db).await;
let uptime_metric = prometheus::register_int_counter!(WORKER_UPTIME_OPTS
let uptime_metric = prometheus::register_counter!(WORKER_UPTIME_OPTS
.clone()
.const_label("name", &worker_name))
.unwrap();
uptime_metric.inc_by(
((Instant::now() - start_time).as_millis() - uptime_metric.get() as u128)
.try_into()
.unwrap(),
);
let worker_execution_duration = prometheus::register_histogram_vec!(
prometheus::HistogramOpts::new(
@@ -465,6 +461,14 @@ pub async fn run_worker(
)
.expect("register prometheus metric");
let worker_execution_duration_counter = prometheus::register_counter!(prometheus::opts!(
"worker_execution_duration_counter",
"Total number of seconds spent executing jobs"
)
.const_label("name", &worker_name))
.expect("register prometheus metric");
let worker_sleep_duration = prometheus::register_histogram!(prometheus::HistogramOpts::new(
"worker_sleep_duration",
"Duration sleeping waiting for job",
@@ -472,6 +476,15 @@ pub async fn run_worker(
.const_label("name", &worker_name),)
.expect("register prometheus metric");
let worker_sleep_duration_counter = prometheus::register_counter!(prometheus::opts!(
"worker_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);

View File

@@ -557,7 +557,7 @@ async fn has_failure_module<'c>(
flow: Uuid,
tx: &mut sqlx::Transaction<'c, sqlx::Postgres>,
) -> Result<bool, Error> {
sqlx::query_scalar(
sqlx::query_scalar::<_, Option<bool>>(
"
SELECT raw_flow->'failure_module' != 'null'::jsonb
FROM queue
@@ -568,6 +568,7 @@ async fn has_failure_module<'c>(
.fetch_one(tx)
.await
.map_err(|e| Error::InternalErr(format!("error during retrieval of has_failure_module: {e}")))
.map(|v| v.unwrap_or(false))
}
fn next_retry(retry: &Retry, status: &RetryStatus) -> Option<(u16, Duration)> {

View File

@@ -1,6 +1,6 @@
// windmill
export { setClient } from "https://deno.land/x/windmill@v1.66.0/mod.ts";
export * from "https://deno.land/x/windmill@v1.66.0/windmill-api/index.ts";
export { setClient } from "https://deno.land/x/windmill@v1.69.3/mod.ts";
export * from "https://deno.land/x/windmill@v1.69.3/windmill-api/index.ts";
// cliffy
export { Command } from "https://deno.land/x/cliffy@v0.25.7/command/command.ts";
@@ -14,7 +14,7 @@ export {
DenoLandProvider,
UpgradeCommand,
} from "https://deno.land/x/cliffy@v0.25.7/command/upgrade/mod.ts";
export { CompletionsCommand } from "https://deno.land/x/cliffy@v0.25.7/command/completions/mod.ts";
// std
export * as path from "https://deno.land/std@0.176.0/path/mod.ts";
export { ensureDir } from "https://deno.land/std@0.176.0/fs/ensure_dir.ts";

View File

@@ -142,7 +142,7 @@ async function push(opts: Options, filePath: string, remotePath: string) {
await requireLogin(opts);
await pushFlow(filePath, workspace.remote, remotePath);
console.log(colors.bold.underline.green("Flow successfully pushed"));
console.log(colors.bold.underline.green("Flow pushed"));
}
export async function pushFlow(

View File

@@ -133,7 +133,7 @@ async function push(opts: GlobalOptions, filePath: string, remotePath: string) {
console.log(colors.bold.yellow("Pushing resource..."));
await pushFolder(workspace.workspaceId, filePath, remotePath);
console.log(colors.bold.underline.green("Resource successfully pushed"));
console.log(colors.bold.underline.green("Resource pushed"));
}
export async function pushFolder(

View File

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

View File

@@ -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.66.1";
const VERSION = "v1.70.1";
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

View File

@@ -12,7 +12,7 @@ export async function downloadZip(
const zipResponse = await fetch(
workspace.remote + "api/w/" + workspace.workspaceId +
"/workspaces/tarball?archive_type=zip",
"/workspaces/tarball?archive_type=zip",
{
headers: requestHeaders,
method: "GET",
@@ -25,8 +25,7 @@ export async function downloadZip(
"Failed to request tarball from API " + zipResponse.statusText,
),
);
console.log(await zipResponse.text());
return undefined;
throw new Error(await zipResponse.text());
}
const blob = await zipResponse.blob();
return await JSZip.loadAsync(blob);

View File

@@ -137,7 +137,7 @@ async function push(opts: PushOptions, filePath: string, name: string) {
console.log(colors.bold.yellow("Pushing resource..."));
await pushResourceType(workspace.workspaceId, filePath, name);
console.log(colors.bold.underline.green("Resource successfully pushed"));
console.log(colors.bold.underline.green("Resource pushed"));
}
async function list(opts: GlobalOptions) {

View File

@@ -155,7 +155,7 @@ async function push(opts: PushOptions, filePath: string, remotePath: string) {
console.log(colors.bold.yellow("Pushing resource..."));
await pushResource(workspace.workspaceId, filePath, remotePath);
console.log(colors.bold.underline.green("Resource successfully pushed"));
console.log(colors.bold.underline.green(`Resource ${remotePath} pushed`));
}
async function list(opts: GlobalOptions) {

View File

@@ -76,7 +76,7 @@ async function push(
await requireLogin(opts);
await pushScript(filePath, contentPath, workspace.workspaceId, remotePath);
console.log(colors.bold.underline.green("Script successfully pushed"));
console.log(colors.bold.underline.green(`Script ${remotePath} pushed`));
}
export async function handleScriptMetadata(path: string, workspace: string, alreadySynced: string[]): Promise<boolean> {

View File

@@ -34,7 +34,7 @@ import { FlowFile } from "./flow.ts";
import { VariableFile } from "./variable.ts";
import { handleFile } from "./script.ts";
import { equal } from "https://deno.land/x/equal/mod.ts";
import { diffCharacters } from "https://deno.land/x/diff/mod.ts";
type DynFSElement = {
isDirectory: boolean;
path: string;
@@ -112,7 +112,7 @@ function ZipFSElement(zip: JSZip): DynFSElement {
}
async function* readDirRecursiveWithIgnore(
ignore: (path: string) => boolean,
ignore: (path: string, isDirectory: boolean) => boolean,
root: DynFSElement,
): AsyncGenerator<
{
@@ -132,7 +132,7 @@ async function* readDirRecursiveWithIgnore(
getContentText(): Promise<string>;
}[] = [{
path: root.path,
ignored: ignore(root.path),
ignored: ignore(root.path, root.isDirectory),
isDirectory: root.isDirectory,
c: root.getChildren,
getContentBytes(): Promise<Uint8Array> {
@@ -150,7 +150,7 @@ async function* readDirRecursiveWithIgnore(
for await (const e2 of e.c()) {
stack.push({
path: e2.path,
ignored: e.ignored || ignore(e2.path),
ignored: e.ignored || ignore(e2.path, e2.isDirectory),
isDirectory: e2.isDirectory,
getContentBytes: e2.getContentBytes,
getContentText: e2.getContentText,
@@ -166,7 +166,7 @@ type Edit = { name: "edited"; path: string; before: string; after: string; };
type Change = Added | Deleted | Edit;
async function elementsToMap(els: DynFSElement, ignore: (path: string) => boolean): Promise<{ [key: string]: string }> {
async function elementsToMap(els: DynFSElement, ignore: (path: string, isDirectory: boolean) => boolean): Promise<{ [key: string]: string }> {
const map: { [key: string]: string } = {};
for await (const entry of readDirRecursiveWithIgnore(
ignore,
@@ -180,7 +180,7 @@ async function elementsToMap(els: DynFSElement, ignore: (path: string) => boolea
}
async function compareDynFSElement(
els1: DynFSElement, els2: DynFSElement,
ignore: (path: string) => boolean,
ignore: (path: string, isDirectory: boolean) => boolean,
raw: boolean
): Promise<Change[]> {
@@ -211,7 +211,29 @@ async function compareDynFSElement(
return changes
}
const isNotWmillFile = (p: string, isDirectory: boolean) => {
if (p.endsWith("/")) {
return false
}
if (isDirectory) {
return !p.startsWith("u/") && !p.startsWith("f/") && !p.startsWith("g/")
}
try {
const typ = getTypeStrFromPath(p)
if (typ == 'resource-type') {
return p.includes('/')
} else {
return !p.startsWith("u/") && !p.startsWith("f/") && !p.startsWith("g/")
}
} catch {
return true
}
}
const isWhitelisted = (p: string) => {
return p == "./" || p == "" || p == "u" || p == "f" || p == "g"
}
async function ignoreF() {
try {
const ignore: {
@@ -220,14 +242,17 @@ async function ignoreF() {
} = gitignore_parser.compile(
await Deno.readTextFile(".wmillignore"),
);
return (p: string) => p.startsWith(".wmill") || ignore.denies(p);
return (p: string, isDirectory: boolean) => {
return !isWhitelisted(p) && (isNotWmillFile(p, isDirectory) || ignore.denies(p));
}
} catch (e) {
return (p: string) => p.startsWith(".wmill");
return (p: string, isDirectory: boolean) => !isWhitelisted(p) && isNotWmillFile(p, isDirectory)
}
}
async function pull(
opts: GlobalOptions & { raw: boolean; yes: boolean },
opts: GlobalOptions & { raw: boolean; yes: boolean, failConflicts: boolean },
) {
@@ -239,7 +264,7 @@ async function pull(
await requireLogin(opts);
console.log("Computing diff local vs remote ...");
console.log(colors.gray("Computing the files to update locally to match remote (taking .wmillignore into account)"));
const remote = ZipFSElement((await downloadZip(workspace))!)
const local = await FSFSElement(path.join(Deno.cwd(), opts.raw ? "" : ".wmill"))
const changes = await compareDynFSElement(remote, local, await ignoreF(), opts.raw)
@@ -250,21 +275,33 @@ async function pull(
prettyChanges(changes)
if (
!opts.yes && !(await Confirm.prompt({ message: `Do you want to apply these ${changes.length} changes?`, default: true }))
!opts.yes && !opts.raw && !(await Confirm.prompt({ message: `Do you want to apply these ${changes.length} changes?`, default: true }))
) {
return
}
console.log(`Applying changes to files ...`);
const conflicts = []
console.log(colors.gray(`Applying changes to files ...`));
for await (const change of changes) {
const target = path.join(Deno.cwd(), change.path);
const stateTarget = path.join(Deno.cwd(), ".wmill", change.path)
if (change.name === "edited") {
try {
if (await Deno.readTextFile(target) !== change.before && !opts.yes) {
const currentLocal = await Deno.readTextFile(target)
if (currentLocal !== change.before) {
console.log(colors.red(`Conflict detected on ${change.path}\nBoth local and remote have been modified.`))
if (await Confirm.prompt("Preserve local (push to change remote and avoid seeing this again)?")) {
if (opts.failConflicts) {
conflicts.push({ local: currentLocal, change, path: change.path })
continue;
} else if (opts.yes) {
console.log(colors.red(`Override local version with remote since --yes was passed and no --fail-conflicts.`))
}
else {
showConflict(change.path, currentLocal, change.after)
if (await Confirm.prompt("Preserve local (push to change remote and avoid seeing this again)?")) {
continue;
}
}
}
} catch { }
@@ -313,10 +350,44 @@ async function pull(
}
}
}
if (opts.failConflicts) {
if (conflicts.length > 0) {
console.error(colors.red(`Conflicts were found`))
console.log("Conflicts:")
for (const conflict of conflicts) {
showConflict(conflict.path, conflict.local, conflict.change.after)
}
console.log(colors.red(`Please resolve theses conflicts manually by either:
- reverting the content back to its remote (\`wmill pull\` and refuse to preserve local when prompted)
- pushing the changes with \`wmill push --skip-pull\` to override wmill with all your local changes
`))
Deno.exit(1)
}
}
console.log(colors.green.underline(`Done! All ${changes.length} changes applied locally.`));
}
function showConflict(path: string, local: string, remote: string) {
console.log(colors.yellow(`- ${path}`))
let finalString = "";
for (const character of diffCharacters(local, remote)) {
if (character.wasRemoved) {
// print red if removed without newline
finalString += `\x1b[31m${character.character}\x1b[0m`;
} else if (character.wasAdded) {
// print green if added
finalString += `\x1b[32m${character.character}\x1b[0m`;
} else {
// print white if unchanged
finalString += `\x1b[37m${character.character}\x1b[0m`;
}
}
console.log(finalString);
console.log("\x1b[31mlocal\x1b[31m - \x1b[32mremote\x1b[32m")
console.log()
}
async function applyDiff(diffs: Difference[], file: string) {
ensureDir(path.dirname(file));
let json;
@@ -386,13 +457,15 @@ function removeSuffix(str: string, suffix: string) {
return str.slice(0, str.length - suffix.length);
}
async function push(opts: GlobalOptions & { raw: boolean, yes: boolean, skipPull: boolean }) {
async function push(opts: GlobalOptions & { raw: boolean, yes: boolean, skipPull: boolean, failConflicts: boolean }) {
if (!opts.raw) {
if (!opts.skipPull) {
console.log("You need to be up-to-date before pushing, pulling first.")
console.log(colors.gray("You need to be up-to-date before pushing, pulling first."))
await pull(opts)
console.log(colors.green("Pull done, now pushing."))
console.log()
}
}
@@ -400,12 +473,12 @@ async function push(opts: GlobalOptions & { raw: boolean, yes: boolean, skipPull
await requireLogin(opts);
console.log("Computing diff remote vs local ...");
console.log(colors.gray("Computing the files to update on the remote to match local (taking .wmillignore into account)"));
const remote = ZipFSElement((await downloadZip(workspace))!)
const local = await FSFSElement(path.join(Deno.cwd(), ""))
const changes = await compareDynFSElement(local, remote, await ignoreF(), opts.raw)
console.log(`local -> remote: ${changes.length} changes to apply`);
console.log(`remote <- local: ${changes.length} changes to apply`);
if (changes.length > 0) {
prettyChanges(changes)
@@ -414,14 +487,20 @@ async function push(opts: GlobalOptions & { raw: boolean, yes: boolean, skipPull
) {
return
}
console.log(`Applying changes to files ...`);
console.log(colors.gray(`Applying changes to files ...`));
const alreadySynced: string[] = []
for await (const change of changes) {
const stateTarget = path.join(Deno.cwd(), ".wmill", change.path)
if (change.name === "edited") {
if (await handleScriptMetadata(change.path, workspace.workspaceId, alreadySynced)) {
if (!opts.raw) {
await Deno.writeTextFile(stateTarget, change.after);
}
continue
} else if (await handleFile(change.path, change.after, workspace.workspaceId, alreadySynced)) {
if (!opts.raw) {
await Deno.writeTextFile(stateTarget, change.after);
}
continue
}
if (!opts.raw) {
@@ -547,6 +626,7 @@ const command = new Command()
.description(
"Pull any remote changes and apply them locally. Use --raw for usage without local state tracking.",
)
.option("--fail-conflicts", "Error on conflicts (both remote and local have changes on the same item)")
.option("--yes", "Pull without needing confirmation")
.option("--raw", "Pull without using state, just overwrite.")
.action(pull as any)
@@ -554,6 +634,7 @@ const command = new Command()
.description(
"Push any local changes and apply them remotely. Use --raw for usage without local state tracking.",
)
.option("--fail-conflicts", "Error on conflicts (both remote and local have changes on the same item)")
.option("--skip-pull", "Push without pulling first")
.option("--yes", "Push without needing confirmation")
.option("--raw", "Push without using state, just overwrite.")

View File

@@ -125,7 +125,7 @@ export function getTypeStrFromPath(
| "folder"
| "app" {
const parsed = path.parse(p);
if (parsed.ext !== ".json") {
if (parsed.ext == ".go" || parsed.ext == ".ts" || parsed.ext == ".sh" || parsed.ext == ".py") {
return 'script'
}

View File

@@ -154,7 +154,7 @@ async function push(opts: GlobalOptions, filePath: string, remotePath: string) {
console.log(colors.bold.yellow("Pushing variable..."));
await pushVariable(workspace.workspaceId, filePath, remotePath);
console.log(colors.bold.underline.green("Variable successfully pushed"));
console.log(colors.bold.underline.green(`Variable ${remotePath} pushed`));
}
export async function pushVariable(

View File

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

View File

@@ -151,7 +151,11 @@ async function switchC(opts: GlobalOptions, workspaceName: string) {
const all = await allWorkspaces();
if (all.findIndex((x) => x.name === workspaceName) === -1) {
console.log(colors.red.bold("! This workspace name does not exist."));
console.log(colors.red.bold(`! This workspace profile ${workspaceName} does not exist locally.`));
console.log("available workspace profiles:")
for (const w of all) {
console.log(' - ' + w.name)
}
return;
}
@@ -184,12 +188,6 @@ export async function add(
workspaceName = await Input.prompt("Name this workspace:");
}
const all = await allWorkspaces();
if (all.findIndex((x) => x.name === workspaceName) !== -1) {
console.log(colors.red.bold("! Workspace name already exists"));
return;
}
if (!workspaceId) {
workspaceId = await Input.prompt({ message: "Enter the ID of this workspace", default: workspaceName, suggestions: [workspaceName] });
}
@@ -219,18 +217,24 @@ export async function add(
token = await loginInteractive(remote);
}
setClient(
token,
remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote,
);
let alreadyExists = false
try {
alreadyExists = await WorkspaceService.existsWorkspace({
requestBody: { id: workspaceId },
})
} catch (e) {
console.log(colors.red.bold("! Credentials or instance is invalid. Aborting."));
throw e
}
if (opts.create) {
setClient(
token,
remote.endsWith("/") ? remote.substring(0, remote.length - 1) : remote,
);
if (
!await WorkspaceService.existsWorkspace({
requestBody: { id: workspaceId },
})
!alreadyExists
) {
console.log(colors.yellow("Workspace does not exist. Creating..."));
console.log(colors.yellow(`Workspace at id ${workspaceId} on ${remote} does not exist. Creating...`));
await WorkspaceService.createWorkspace({
requestBody: {
id: workspaceId,
@@ -239,6 +243,14 @@ export async function add(
},
});
}
} else if (!alreadyExists) {
console.log(colors.red.bold(`! Workspace at id ${workspaceId} on ${remote} does not exist. Re-run with --create to create it. Aborting.`));
console.log("On that instance and with those credentials, the workspaces that you can access are:")
const workspaces = await WorkspaceService.listWorkspaces()
for (const workspace of workspaces) {
console.log(`- ${workspace.id} (name: ${workspace.name})`)
}
Deno.exit(1);
}
await addWorkspace({
@@ -246,28 +258,40 @@ export async function add(
remote: remote,
workspaceId: workspaceId,
token: token,
});
}, opts);
await Deno.writeTextFile(
(await getRootStore()) + "/activeWorkspace",
workspaceName,
);
console.log(colors.green.underline("Succesfully added workspace!"));
console.log(colors.green.underline(`Added workspace ${workspaceName} for ${workspaceId} on ${remote}!`));
}
export async function addWorkspace(workspace: Workspace) {
export async function addWorkspace(workspace: Workspace, opts: any) {
workspace.remote = new URL(workspace.remote).toString(); // add trailing slash in all cases!
const file = await Deno.open((await getRootStore()) + "remotes.ndjson", {
append: true,
write: true,
read: false,
read: true,
create: true,
});
await removeWorkspace(workspace.name, true, opts);
await file.write(new TextEncoder().encode(JSON.stringify(workspace) + "\n"));
file.close();
}
export async function removeWorkspace(name: string) {
export async function removeWorkspace(name: string, silent: boolean, opts: any) {
const orgWorkspaces = await allWorkspaces();
if (orgWorkspaces.findIndex((x) => x.name === name) === -1) {
if (!silent) {
console.log(colors.red.bold(`! Workspace profile ${name} does not exist locally`));
console.log("available workspace profiles:")
await list(opts)
}
return;
}
if (silent) {
console.log(colors.yellow(`Replacing existing workspace ${name}`))
}
await Deno.writeTextFile(
(await getRootStore()) + "remotes.ndjson",
orgWorkspaces
@@ -275,19 +299,22 @@ export async function removeWorkspace(name: string) {
.map((x) => JSON.stringify(x))
.join("\n"),
);
if (!silent) {
console.log(colors.green.underline(`Succesfully removed workspace ${name}!`));
}
}
async function remove(_opts: GlobalOptions, name: string) {
await removeWorkspace(name);
console.log(colors.green.underline("Succesfully removed workspace!"));
await removeWorkspace(name, false, _opts);
}
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")

View File

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

View File

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

View File

@@ -1,22 +1,26 @@
{
"name": "windmill",
"version": "1.66.1",
"version": "1.70.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "windmill",
"version": "1.66.1",
"version": "1.70.1",
"dependencies": {
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@leeoniya/ufuzzy": "^0.9.1",
"@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",
@@ -26,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",
@@ -41,6 +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.4",
"@windmill-labs/svelvet": "^4.0.20",
"@zerodevx/svelte-toast": "^0.8.1",
"autoprefixer": "^10.4.13",
@@ -60,7 +65,6 @@
"svelte": "^3.55.1",
"svelte-awesome": "^3.0.0",
"svelte-check": "^3.0.2",
"svelte-grid": "^5.1.1",
"svelte-highlight": "^6.2.1",
"svelte-overlay": "^1.4.1",
"svelte-popperjs": "^1.3.2",
@@ -600,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": {
@@ -750,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": {
@@ -775,8 +782,6 @@
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
"dev": true,
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@@ -1262,6 +1267,12 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@windmill-labs/svelte-grid": {
"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": {
"version": "4.0.20",
"resolved": "https://registry.npmjs.org/@windmill-labs/svelvet/-/svelvet-4.0.20.tgz",
@@ -1351,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",
@@ -1865,8 +1893,7 @@
"node_modules/chart.js": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
"peer": true
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
},
"node_modules/chartjs-adapter-date-fns": {
"version": "3.0.0",
@@ -2434,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",
@@ -2966,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",
@@ -3844,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"
}
@@ -4239,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"
@@ -4473,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"
@@ -4567,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"
@@ -6177,33 +6213,14 @@
}
},
"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"
"@floating-ui/core": "^1.1.0",
"@floating-ui/dom": "^1.1.0"
}
},
"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"
}
},
"node_modules/svelte-grid": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/svelte-grid/-/svelte-grid-5.1.1.tgz",
"integrity": "sha512-PJTC4PUejb8RzcUjymWnf1HALqseUBwxl+p+i5uJlDIC1+zXKok1J16IDoHQxXhNj+INcF9KHE7hIm++NurSAQ==",
"dev": true
},
"node_modules/svelte-highlight": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/svelte-highlight/-/svelte-highlight-6.2.1.tgz",
@@ -6325,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": {
@@ -6668,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"
@@ -7463,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": {
@@ -7579,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": {
@@ -7597,9 +7616,7 @@
"@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
"dev": true,
"peer": true
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
},
"@redocly/json-to-json-schema": {
"version": "0.0.1",
@@ -7906,6 +7923,12 @@
"eslint-visitor-keys": "^3.3.0"
}
},
"@windmill-labs/svelte-grid": {
"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": {
"version": "4.0.20",
"resolved": "https://registry.npmjs.org/@windmill-labs/svelvet/-/svelvet-4.0.20.tgz",
@@ -7977,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",
@@ -8321,8 +8358,7 @@
"chart.js": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
"peer": true
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
},
"chartjs-adapter-date-fns": {
"version": "3.0.0",
@@ -8741,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",
@@ -9149,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",
@@ -9824,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"
}
@@ -10128,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"
@@ -10299,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"
@@ -10372,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": {
@@ -11494,31 +11539,14 @@
}
},
"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-grid": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/svelte-grid/-/svelte-grid-5.1.1.tgz",
"integrity": "sha512-PJTC4PUejb8RzcUjymWnf1HALqseUBwxl+p+i5uJlDIC1+zXKok1J16IDoHQxXhNj+INcF9KHE7hIm++NurSAQ==",
"dev": true
},
"svelte-highlight": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/svelte-highlight/-/svelte-highlight-6.2.1.tgz",
@@ -11582,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": {
@@ -11838,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",

View File

@@ -1,6 +1,6 @@
{
"name": "windmill",
"version": "1.66.1",
"version": "1.70.1",
"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,6 +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.4",
"@windmill-labs/svelvet": "^4.0.20",
"@zerodevx/svelte-toast": "^0.8.1",
"autoprefixer": "^10.4.13",
@@ -44,7 +45,6 @@
"svelte": "^3.55.1",
"svelte-awesome": "^3.0.0",
"svelte-check": "^3.0.2",
"svelte-grid": "^5.1.1",
"svelte-highlight": "^6.2.1",
"svelte-overlay": "^1.4.1",
"svelte-popperjs": "^1.3.2",
@@ -63,12 +63,16 @@
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@leeoniya/ufuzzy": "^0.9.1",
"@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",
@@ -78,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"
},

View File

@@ -9,7 +9,7 @@ declare namespace svelte.JSX {
}
}
declare module 'svelte-grid' {
declare module '@windmill-labs/svelte-grid' {
import type { SvelteComponentTyped } from 'svelte'
export interface Size {
@@ -37,14 +37,14 @@ declare module 'svelte-grid' {
export interface Props<T> {
fillSpace?: boolean
items: FilledItem<T>[],
items: FilledItem<T>[]
rowHeight: number
cols: [number, number][]
gap?: [number, number]
fastStart?: boolean
throttleUpdate?: number
throttleResize?: number
onTopId?: string
scroller?: undefined
sensor?: number
}
@@ -63,8 +63,8 @@ declare module 'svelte-grid' {
> { }
}
declare module 'svelte-grid/build/helper/index.mjs' {
import { ItemLayout } from 'svelte-grid'
declare module '@windmill-labs/svelte-grid/build/helper/index.mjs' {
import { ItemLayout } from '@windmill-labs/svelte-grid'
const x: {
normalize(items: any[], col: any): unknown[]

View File

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

View File

@@ -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&nbsp;<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>

View File

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

View File

@@ -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%">

View File

@@ -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

View File

@@ -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

View File

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

View File

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

View File

@@ -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 ?? '')}>

View File

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

View File

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

View File

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

View File

@@ -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}

View File

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

View File

@@ -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>

View File

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

View File

@@ -1,25 +0,0 @@
<script lang="ts">
import DisplayResult from '$lib/components/DisplayResult.svelte'
import { getContext } from 'svelte'
import type { AppInput } from '../inputType'
import { IS_APP_PUBLIC_CONTEXT_KEY } from '../types'
import RunnableWrapper from './helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let initializing: boolean | undefined = undefined
const requireHtmlApproval = getContext<boolean | undefined>(IS_APP_PUBLIC_CONTEXT_KEY)
let result: any = undefined
export const staticOutputs: string[] = ['result', 'loading']
</script>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
<div class="w-full border-b px-2 text-xs p-1 font-semibold bg-gray-500 text-white rounded-t-sm">
Results
</div>
<div class="p-2">
<DisplayResult {result} {requireHtmlApproval} />
</div>
</RunnableWrapper>

View File

@@ -1,9 +1,9 @@
<script lang="ts">
import { Button, type ButtonType } from '$lib/components/common'
import { getContext, onMount } from 'svelte'
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 type RunnableComponent from '../helpers/RunnableComponent.svelte'
@@ -20,7 +20,7 @@
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let noWFull = false
export let preclickAction: (() => Promise<void>) | undefined = undefined
export let customCss: Record<'button', { class: string; style: string }> | undefined = undefined
export let customCss: ComponentCustomCSS<'button'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
@@ -95,7 +95,6 @@
<InputValue {id} input={configuration.triggerOnAppLoad} bind:value={triggerOnAppLoad} />
<InputValue
row={extraQueryParams['row']}
{id}
input={configuration.disabled}
bind:value={disabled}
@@ -119,10 +118,10 @@
<Button
btnClasses={twMerge(
$app.css?.['buttoncomponent']?.['button']?.class,
customCss?.button?.class,
customCss?.button.class,
fillContainer ? 'w-full h-full' : ''
)}
style={[$app.css?.['buttoncomponent']?.['button']?.style, customCss?.button?.style].join(';')}
style={[$app.css?.['buttoncomponent']?.['button']?.style, customCss?.button.style].join(';')}
{disabled}
on:pointerdown={(e) => {
e?.stopPropagation()

View File

@@ -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'))

View File

@@ -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
}}

View File

@@ -0,0 +1,3 @@
export { default as AppButton } from './AppButton.svelte'
export { default as AppForm } from './AppForm.svelte'
export { default as AppFormButton } from './AppFormButton.svelte'

View File

@@ -11,16 +11,22 @@
CategoryScale,
BarElement
} from 'chart.js'
import type { ChartOptions } from 'chart.js'
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,
@@ -45,7 +51,18 @@
theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e']
}[theme]
const options = {
const lineOptions: ChartOptions<'line'> = {
responsive: true,
animation: false,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
}
}
const barOptions: ChartOptions<'bar'> = {
responsive: true,
animation: false,
maintainAspectRatio: false,
@@ -65,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} />
{:else}
<Bar {data} {options} />
<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>

View File

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

View File

@@ -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

View File

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

View File

@@ -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>

View File

@@ -9,22 +9,29 @@
LinearScale,
PointElement,
CategoryScale,
BarElement
BarElement,
type Point
} from 'chart.js'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { AppInput } from '../../inputType'
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,
@@ -59,18 +66,22 @@
}
}
}
}
} as ChartOptions<'scatter'>
$: 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>

View File

@@ -8,7 +8,7 @@
import InputValue from '../helpers/InputValue.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import { twMerge } from 'tailwind-merge'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { getContext } from 'svelte'
export let id: string
@@ -17,7 +17,7 @@
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: Record<'text', { class: string; style: string }> | undefined = undefined
export let customCss: ComponentCustomCSS<'text'> | undefined = undefined
export const staticOutputs: string[] = ['result', 'loading']

View File

@@ -12,19 +12,26 @@
CategoryScale,
BarElement,
TimeScale,
LogarithmicScale
LogarithmicScale,
type Point
} from 'chart.js'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { AppInput } from '../../inputType'
import Scatter from 'svelte-chartjs/Scatter.svelte'
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
@@ -73,11 +80,13 @@
type: logarithmicScale ? 'logarithmic' : 'linear'
}
}
}
} as ChartOptions<'scatter'>
$: data = {
datasets: result ?? []
}
} as ChartData<'scatter', (number | Point)[], unknown>
$: css = concatCustomCss($app.css?.timeseriescomponent, customCss)
</script>
<InputValue {id} input={configuration.logarithmicScale} bind:value={logarithmicScale} />
@@ -85,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>

View File

@@ -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>

View File

@@ -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>

View File

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

View File

@@ -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>

View File

@@ -1,25 +1,30 @@
<script lang="ts">
import { getContext, onMount } from 'svelte'
import type { Output } from '../../rx'
import type { AppEditorContext, BaseAppComponent } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
import type { AppInput } from '../../inputType'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { Output } from '../../../rx'
import type { AppEditorContext, BaseAppComponent, ComponentCustomCSS } from '../../../types'
import InputValue from '../../helpers/InputValue.svelte'
import type { AppInput } from '../../../inputType'
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
import { writable } from 'svelte/store'
import { createSvelteTable, flexRender, type TableOptions } from '@tanstack/svelte-table'
import AppButton from '../buttons/AppButton.svelte'
import AppButton from '../../buttons/AppButton.svelte'
import { classNames, isObject } from '$lib/utils'
import DebouncedInput from '../helpers/DebouncedInput.svelte'
import DebouncedInput from '../../helpers/DebouncedInput.svelte'
import AppTableFooter from './AppTableFooter.svelte'
import { tableOptions } from './tableOptions'
import Alert from '$lib/components/common/alert/Alert.svelte'
import type { ButtonComponent } from '../../editor/Component.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">

View File

@@ -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

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import type { ConnectedAppInput, RowAppInput, StaticAppInput, UserAppInput } from '../inputType'
import type { InlineScript } from '../types'
import RunnableComponent from './helpers/RunnableComponent.svelte'
import type { ConnectedAppInput, RowAppInput, StaticAppInput, UserAppInput } from '../../inputType'
import type { InlineScript } from '../../types'
import RunnableComponent from './RunnableComponent.svelte'
export let id: string
export let name: string

View File

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

View File

@@ -25,6 +25,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
@@ -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} />

View File

@@ -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>

View File

@@ -1,5 +1,6 @@
export { default as AlignWrapper } from './AlignWrapper.svelte'
export { default as DebouncedInput } from './DebouncedInput.svelte'
export { default as HiddenComponent } from './HiddenComponent.svelte'
export { default as InputDefaultValue } from './InputDefaultValue.svelte'
export { default as InputValue } from './InputValue.svelte'
export { default as MissingConnectionWarning } from './MissingConnectionWarning.svelte'

View File

@@ -0,0 +1,6 @@
export * from './buttons'
export * from './display'
export * from './inputs'
export * from './layout'
export * from './helpers'

View File

@@ -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']
@@ -26,7 +28,9 @@
result: Output<boolean>
}
$: defaultValue != undefined && outputs.result.set(defaultValue)
$: 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)
}}

View File

@@ -35,7 +35,9 @@
accept={acceptedFileTypes?.length ? acceptedFileTypes?.join(', ') : undefined}
multiple={allowMultiple}
convertToBase64
on:change={({detail}) => {handleChange(detail)}}
on:change={({ detail }) => {
handleChange(detail)
}}
class="w-full h-full"
>
{text}

View File

@@ -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,17 +47,29 @@
}
})
: []
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)
}
}
function onChange(e: CustomEvent) {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
outputs?.result.set(JSON.parse(e.detail?.['value']) || undefined)
let result: any = undefined
try {
result = JSON.parse(e.detail?.['value'])
} catch (_) {}
outputs?.result.set(result)
}
$: css = concatCustomCss($app.css?.selectcomponent, customCss)
</script>
<InputValue {id} input={configuration.items} bind:value={items} />
@@ -56,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={() => {
@@ -70,12 +93,21 @@
$selectedComponent = id
}
}}
on:focus={() => {
$selectedComponent = id
}}
floatingConfig={{
strategy: 'fixed'
}}
/>
</div>
</AlignWrapper>
<style global>
.app-select .value-container {
@apply p-0 !important;
padding: 0 !important;
}
.svelte-select-list {
z-index: 1000 !important;
}
</style>

View File

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

View File

@@ -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'
@@ -12,8 +13,9 @@
export let inputType = 'text'
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 placeholder: string | undefined = undefined
@@ -28,6 +30,8 @@
}
$: input && handleInput()
$: css = concatCustomCss($app.css?.textinputcomponent, customCss)
</script>
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
@@ -36,7 +40,8 @@
<AlignWrapper {verticalAlignment}>
<input
class="mx-0.5"
class="mx-0.5 {css?.input?.class ?? ''}"
style={css?.input?.style ?? ''}
on:focus={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type { AppInput } from '../../../inputType'
import type { Output } from '../../../rx'
import type { AppEditorContext } from '../../../types'
import AlignWrapper from '../../helpers/AlignWrapper.svelte'
import InputValue from '../../helpers/InputValue.svelte'
import CurrencyInput from './CurrencyInput.svelte'
export let id: string

View File

@@ -0,0 +1,9 @@
export { default as AppCheckbox } from './AppCheckbox.svelte'
export { default as AppCurrencyInput } from './currency/AppCurrencyInput.svelte'
export { default as AppDateInput } from './AppDateInput.svelte'
export { default as AppFileInput } from './AppFileInput.svelte'
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'

View File

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

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import type { AppInput } from '../inputType'
import type { HorizontalAlignment, VerticalAlignment } from '../types'
import AlignWrapper from './helpers/AlignWrapper.svelte'
import InputValue from './helpers/InputValue.svelte'
import type { AppInput } from '../../inputType'
import type { HorizontalAlignment, VerticalAlignment } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: Record<string, AppInput>

View File

@@ -0,0 +1,85 @@
<script lang="ts">
import { Tab, Tabs } from '$lib/components/common'
import { getContext } from 'svelte'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext, GridItem } from '../../types'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: Record<string, AppInput>
export let componentContainerHeight: number
export let tabs: string[]
export const staticOutputs: string[] = ['selectedTabIndex']
const { app, worldStore, focusedGrid, selectedComponent } =
getContext<AppEditorContext>('AppEditorContext')
let selected: string = ''
let noPadding: boolean | undefined = undefined
$: selectedIndex = tabs?.indexOf(selected) ?? -1
$: if ((tabs && selected === '') || !tabs.includes(selected)) {
selected = tabs[0]
}
$: outputs = $worldStore?.outputsById[id] as {
selectedTabIndex: Output<number | null>
}
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()
let tabHeight: number = 0
function onFocus() {
$focusedGrid = {
parentComponentId: id,
subGridIndex: selectedIndex ?? 0
}
}
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
</script>
<InputValue {id} input={configuration.tabs} bind:value={tabs} />
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<div>
<div bind:clientHeight={tabHeight} on:pointerdown|stopPropagation>
<Tabs bind:selected>
{#each tabs ?? [] as res}
<Tab value={res}>
<span class="font-semibold">{res}</span>
</Tab>
{/each}
</Tabs>
</div>
{#if $app.subgrids}
{#each tabs ?? [] as res, i}
<SubGridEditor
visible={i === selectedIndex}
bind:subGrid={$app.subgrids[`${id}-${i}`]}
{noPadding}
containerHeight={componentContainerHeight - tabHeight}
on:focus={() => {
$selectedComponent = id
}}
/>
{/each}
{/if}
</div>

View File

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

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { components, type AppComponent } from './Component.svelte'
import { components, type AppComponent } from './component'
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
export let component: AppComponent

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import type { ConnectedAppInput, RowAppInput, StaticAppInput, UserAppInput } from '../inputType'
import type { AppComponent } from './Component.svelte'
import type { AppComponent } from './component'
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>

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