Compare commits
4 Commits
rf/fixGrap
...
rf/debugKa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ece4573076 | ||
|
|
833d0df965 | ||
|
|
1e7b7cc8d6 | ||
|
|
1de8eefe96 |
12
.github/uffizzi/docker-compose.uffizzi.yml
vendored
12
.github/uffizzi/docker-compose.uffizzi.yml
vendored
@@ -14,13 +14,13 @@ services:
|
||||
|
||||
windmill:
|
||||
image: '${WINDMILL_IMAGE}'
|
||||
privileged: false
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8000:8000
|
||||
entrypoint: ['/bin/sh', '-c']
|
||||
command: 'echo ${OAUTH_JSON_BASE64} | base64 --decode > /usr/src/app/oauth.json && ./windmill'
|
||||
environment:
|
||||
- DATABASE_URL=postgres://postgres:changeme@localhost/windmill?sslmode=disable
|
||||
- BASE_URL=${EXPECTED_URL}
|
||||
- BASE_URL=http://localhost
|
||||
- BASE_INTERNAL_URL=http://localhost:8000
|
||||
- RUST_LOG=info
|
||||
- NUM_WORKERS=3
|
||||
@@ -28,16 +28,12 @@ services:
|
||||
- DENO_PATH=/usr/bin/deno
|
||||
- PYTHON_PATH=/usr/local/bin/python3
|
||||
- METRICS_ADDR=false
|
||||
- OAUTH_JSON_BASE64=${OAUTH_JSON_BASE64}
|
||||
volumes:
|
||||
- worker_dependency_cache:/tmp/windmill/cache
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 250M
|
||||
|
||||
lsp:
|
||||
image: '${LSP_IMAGE}'
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 3001:3001
|
||||
|
||||
|
||||
2
.github/workflows/automerge-dependabot.yml
vendored
2
.github/workflows/automerge-dependabot.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v1.3.6
|
||||
uses: dependabot/fetch-metadata@v1.3.5
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
|
||||
47
.github/workflows/docker-310.yml
vendored
47
.github/workflows/docker-310.yml
vendored
@@ -1,47 +0,0 @@
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
name: Build and push windmill with python 3.10 and openbb
|
||||
on: workflow_dispatch
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}-openbb
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build_ee:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# - name: Set up Docker Buildx
|
||||
# uses: docker/setup-buildx-action@v2
|
||||
|
||||
- uses: depot/setup-action@v1
|
||||
|
||||
- name: Login to registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push publicly ee
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
file: ./docker/DockerfileOpenbb
|
||||
build-args: |
|
||||
features=enterprise
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:openbb
|
||||
labels: |
|
||||
org.opencontainers.image.licenses=Windmill-Enterprise-License
|
||||
2
.github/workflows/uffizzi-build.yml
vendored
2
.github/workflows/uffizzi-build.yml
vendored
@@ -4,8 +4,6 @@ on:
|
||||
types: [opened,synchronize,reopened,closed]
|
||||
paths:
|
||||
- "backend/**"
|
||||
- ".github/uffizzi/**"
|
||||
- ".github/workflows/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
27
.github/workflows/uffizzi-preview.yml
vendored
27
.github/workflows/uffizzi-preview.yml
vendored
@@ -47,35 +47,22 @@ jobs:
|
||||
echo 'EVENT_JSON<<EOF' >> $GITHUB_ENV
|
||||
cat event.json >> $GITHUB_ENV
|
||||
echo 'EOF' >> $GITHUB_ENV
|
||||
- name: Read PR Number From Event Object
|
||||
id: pr
|
||||
run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV
|
||||
- name: Predict Deployment URL
|
||||
id: url
|
||||
# Replace dots in the repo name with the plus sign
|
||||
run: |
|
||||
REPO=$(echo ${{ github.repository }} | sed 's/\./+/g')
|
||||
echo "EXPECTED_URL=https://app.uffizzi.com/github.com/$REPO/pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
|
||||
- name: Re-Render Compose File
|
||||
run: |
|
||||
OAUTH_JSON_BASE64=${{ secrets.OAUTH_JSON_BASE64 }}
|
||||
export OAUTH_JSON_BASE64
|
||||
envsubst '${OAUTH_JSON_BASE64} ${EXPECTED_URL}' < docker-compose.rendered.yml > docker-compose.uffizzi.yml
|
||||
# cat docker-compose.uffizzi.yml
|
||||
|
||||
- name: Hash Rendered Compose File
|
||||
id: hash
|
||||
# If the previous workflow was triggered by a PR close event, we will not have a compose file artifact.
|
||||
if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }}
|
||||
run: echo "COMPOSE_FILE_HASH=$(md5sum docker-compose.uffizzi.yml | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
run: echo "COMPOSE_FILE_HASH=$(md5sum docker-compose.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
- name: Cache Rendered Compose File
|
||||
if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }}
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: docker-compose.uffizzi.yml
|
||||
path: docker-compose.rendered.yml
|
||||
key: ${{ env.COMPOSE_FILE_HASH }}
|
||||
|
||||
- name: Read PR Number From Event Object
|
||||
id: pr
|
||||
run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV
|
||||
|
||||
- name: DEBUG - Print Job Outputs
|
||||
if: ${{ runner.debug }}
|
||||
run: |
|
||||
@@ -93,7 +80,7 @@ jobs:
|
||||
# If this workflow was triggered by a PR close event, cache-key will be an empty string
|
||||
# and this reusable workflow will delete the preview deployment.
|
||||
compose-file-cache-key: ${{ needs.cache-compose-file.outputs.compose-file-cache-key }}
|
||||
compose-file-cache-path: docker-compose.uffizzi.yml
|
||||
compose-file-cache-path: docker-compose.rendered.yml
|
||||
server: https://app.uffizzi.com
|
||||
pr-number: ${{ needs.cache-compose-file.outputs.pr-number }}
|
||||
permissions:
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"python.analysis.typeCheckingMode": "basic"
|
||||
}
|
||||
65
CHANGELOG.md
65
CHANGELOG.md
@@ -1,71 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## [1.61.1](https://github.com/windmill-labs/windmill/compare/v1.61.0...v1.61.1) (2023-01-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **backend:** compile issue ([df8cc1f](https://github.com/windmill-labs/windmill/commit/df8cc1f2482b3d8b1530cdaef1361303ff5cadff))
|
||||
|
||||
## [1.61.0](https://github.com/windmill-labs/windmill/compare/v1.60.0...v1.61.0) (2023-01-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add openapi viewer ([#1094](https://github.com/windmill-labs/windmill/issues/1094)) ([1337811](https://github.com/windmill-labs/windmill/commit/1337811438d48e23133f68e9157bd185d5fe4a82))
|
||||
* add PIP_LOCAL_DEPENDENCIES ([b7db4c7](https://github.com/windmill-labs/windmill/commit/b7db4c78c4629f1fd2dfd7a338f783b16f07b24d))
|
||||
* add QUEUE_LIMIT_WAIT_RESULT ([51a8810](https://github.com/windmill-labs/windmill/commit/51a8810aa0a9ab7702df459dd270278d42bd3899))
|
||||
* add resource and resource type from json ([080ecb0](https://github.com/windmill-labs/windmill/commit/080ecb04d7a08d035fe07f179975b52bc0f77297))
|
||||
* add sql as a valid type in Python ([0172587](https://github.com/windmill-labs/windmill/commit/0172587b129ce54d96dc99336a1f56c66ebdbef5))
|
||||
* add sync webhook for flows ([f377c84](https://github.com/windmill-labs/windmill/commit/f377c84f5a2148a2bbb7c16e93f13e1d85ceb17e))
|
||||
* **backend:** add queue_limit + configurable timeout + fix timeout cancel ([eef3bab](https://github.com/windmill-labs/windmill/commit/eef3bab6e4d9f1af1435db868c707a692558ab74))
|
||||
* **deno:** add support for DENO_AUTH_TOKENS ([832ddab](https://github.com/windmill-labs/windmill/commit/832ddabdf2239521368e5f96df144abce0db31c2))
|
||||
* **deno:** allow overriding deno sandboxing with DENO_FLAGS' ([7f40373](https://github.com/windmill-labs/windmill/commit/7f40373fd64005d87972854a565c6cf521232982))
|
||||
* **frontend:** Add app inputs configurations ([#1142](https://github.com/windmill-labs/windmill/issues/1142)) ([3ed16b8](https://github.com/windmill-labs/windmill/commit/3ed16b88a42e4db6e12f8557c5bbaa2d832b1c17))
|
||||
* **frontend:** Add app preview lock ([#1127](https://github.com/windmill-labs/windmill/issues/1127)) ([6a88e8c](https://github.com/windmill-labs/windmill/commit/6a88e8c4f4d6fa5c393ce27b2040784a74a73b06))
|
||||
* **frontend:** Add copy button option to app text display component ([#1090](https://github.com/windmill-labs/windmill/issues/1090)) ([bdfc38d](https://github.com/windmill-labs/windmill/commit/bdfc38d954a3c5548fb7f9ee6f80f741eff8cb67))
|
||||
* **frontend:** Add default codes to app editor ([#1099](https://github.com/windmill-labs/windmill/issues/1099)) ([c50c740](https://github.com/windmill-labs/windmill/commit/c50c7406f267b480af2a01b47e3fcfa1d763db7a))
|
||||
* **frontend:** Add HTML result rendering ([#1160](https://github.com/windmill-labs/windmill/issues/1160)) ([c01bf70](https://github.com/windmill-labs/windmill/commit/c01bf70f62680a4b77812ac6eb64aca2b15d9a8d))
|
||||
* **frontend:** Add more integration icons ([#1097](https://github.com/windmill-labs/windmill/issues/1097)) ([2191e85](https://github.com/windmill-labs/windmill/commit/2191e852318f069489f77a4f1c44aadf248c7f53))
|
||||
* **frontend:** add plotly support ([a4f8f9e](https://github.com/windmill-labs/windmill/commit/a4f8f9e1cf80395d5cd1229c8dd5dda244e2ba7f))
|
||||
* **frontend:** add selectedRowIndex to the table outputs ([#1145](https://github.com/windmill-labs/windmill/issues/1145)) ([f05f9e4](https://github.com/windmill-labs/windmill/commit/f05f9e4edb928e7a8e3e66a62de9c6487684a14b))
|
||||
* **frontend:** Add Supabase resource ([#1107](https://github.com/windmill-labs/windmill/issues/1107)) ([12b00a8](https://github.com/windmill-labs/windmill/commit/12b00a808d1f12827a7bc26518cc6f972bdde917))
|
||||
* **frontend:** add support for background scripts + add FormButtonCo… ([#1124](https://github.com/windmill-labs/windmill/issues/1124)) ([e969af9](https://github.com/windmill-labs/windmill/commit/e969af9e44d1b4409064080e8662552ee3e262e8))
|
||||
* **frontend:** Add surreal db logo ([#1102](https://github.com/windmill-labs/windmill/issues/1102)) ([d811675](https://github.com/windmill-labs/windmill/commit/d81167588227f2cc433aab64551d96d21a589c5b))
|
||||
* **frontend:** Add tooltip to app recompute ([#1122](https://github.com/windmill-labs/windmill/issues/1122)) ([4dfdf37](https://github.com/windmill-labs/windmill/commit/4dfdf374af358ef46ee8057373546719c6570067))
|
||||
* **frontend:** add vega-lite component ([bd79938](https://github.com/windmill-labs/windmill/commit/bd79938bed6da3875a4a2dd72dad14dedbf25ddf))
|
||||
* **frontend:** Display error as an icon in order to avoid clutter wh… ([#1143](https://github.com/windmill-labs/windmill/issues/1143)) ([22b8fed](https://github.com/windmill-labs/windmill/commit/22b8fed9d904a37aae66f6d957f4987f6ca9955c))
|
||||
* **frontend:** Open debug runs from component ([#1155](https://github.com/windmill-labs/windmill/issues/1155)) ([73bc13b](https://github.com/windmill-labs/windmill/commit/73bc13bb7d4b1eb25a3a726ac9e6bb80120a495f))
|
||||
* **frontend:** Update app table component styles ([#1100](https://github.com/windmill-labs/windmill/issues/1100)) ([172b5db](https://github.com/windmill-labs/windmill/commit/172b5dba8f4c3aaf11569c72313ad74845c668a6))
|
||||
* **python:** add support for extra args in python ([772c768](https://github.com/windmill-labs/windmill/commit/772c768cda094f208a5efb7aab03eee3a8f38f68))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** Add default value for text, number and date input + fix issues with number input + add date input in the settings panel ([#1135](https://github.com/windmill-labs/windmill/issues/1135)) ([8f90602](https://github.com/windmill-labs/windmill/commit/8f906026b3203702c3b6a30bcac9fb2aca985c29))
|
||||
* **frontend:** Add highlight to selected workspace ([#1159](https://github.com/windmill-labs/windmill/issues/1159)) ([f221a6c](https://github.com/windmill-labs/windmill/commit/f221a6c17f145d0c42f7faf785c37f4037308973))
|
||||
* **frontend:** add missing condition to properly select first row ([#1128](https://github.com/windmill-labs/windmill/issues/1128)) ([3d873ed](https://github.com/windmill-labs/windmill/commit/3d873ed51c769005981a8d8dfb95faa3ca33bb83))
|
||||
* **frontend:** App form component display ([#1096](https://github.com/windmill-labs/windmill/issues/1096)) ([339742c](https://github.com/windmill-labs/windmill/commit/339742ca77dd0fda19d5a262617e42c341ef5871))
|
||||
* **frontend:** App script list panel overflow ([#1101](https://github.com/windmill-labs/windmill/issues/1101)) ([7bc59d9](https://github.com/windmill-labs/windmill/commit/7bc59d9d2650b623a2b481a727ffc495b4216f22))
|
||||
* **frontend:** App table action button cell ([#1149](https://github.com/windmill-labs/windmill/issues/1149)) ([e989662](https://github.com/windmill-labs/windmill/commit/e98966283dd9b57cc07da34876a90d19210c2927))
|
||||
* **frontend:** App table header z-index ([#1120](https://github.com/windmill-labs/windmill/issues/1120)) ([59c4cc2](https://github.com/windmill-labs/windmill/commit/59c4cc2058f86deea793b61de59e2936e50e5577))
|
||||
* **frontend:** Check if hiddenInlineScripts are undefined before iterating over them ([#1134](https://github.com/windmill-labs/windmill/issues/1134)) ([71a443e](https://github.com/windmill-labs/windmill/commit/71a443e3c56d2b8c951de6e3701a411ad1a0ce34))
|
||||
* **frontend:** fix first row selection ([#1125](https://github.com/windmill-labs/windmill/issues/1125)) ([6c9daf7](https://github.com/windmill-labs/windmill/commit/6c9daf70021859dcd7cef717bc3acdfa88cffd02))
|
||||
* **frontend:** Fix id generation when a second action ([#1110](https://github.com/windmill-labs/windmill/issues/1110)) ([4f86981](https://github.com/windmill-labs/windmill/commit/4f869811fee73826b2b10965241d2d8dba59dc2a))
|
||||
* **frontend:** Make sure AppSelect items are an array ([#1144](https://github.com/windmill-labs/windmill/issues/1144)) ([24b1fa0](https://github.com/windmill-labs/windmill/commit/24b1fa0ae327c984841f9ed8b163b3fccc6da258))
|
||||
* **frontend:** Make sure that old apps are rendering properly ([#1132](https://github.com/windmill-labs/windmill/issues/1132)) ([a78486d](https://github.com/windmill-labs/windmill/commit/a78486d7e08f76e22406063288b35e9030974d7a))
|
||||
* **frontend:** Playwright ([#1108](https://github.com/windmill-labs/windmill/issues/1108)) ([f0435f5](https://github.com/windmill-labs/windmill/commit/f0435f5f81941c5b49500003aa27956d627daadb))
|
||||
* **frontend:** Prepare app scripts code for export ([#1123](https://github.com/windmill-labs/windmill/issues/1123)) ([173093a](https://github.com/windmill-labs/windmill/commit/173093a40321f6ad35bf766a5554b21cea388771))
|
||||
* **frontend:** Prevent modal from hijacking all keypress event ([#1136](https://github.com/windmill-labs/windmill/issues/1136)) ([aa6de3b](https://github.com/windmill-labs/windmill/commit/aa6de3bb5746b9d99c8e3a52e6a9fff10d97bc6a))
|
||||
* **frontend:** Revert component input panel change ([#1092](https://github.com/windmill-labs/windmill/issues/1092)) ([0419e7e](https://github.com/windmill-labs/windmill/commit/0419e7e1c9239fd3cbc49acf82a73e9c01938153))
|
||||
* **frontend:** Runnable table overflow ([#1119](https://github.com/windmill-labs/windmill/issues/1119)) ([462adbe](https://github.com/windmill-labs/windmill/commit/462adbe42f823646413a5003fd71f3dd473c0728))
|
||||
* **frontend:** Select the first row by default, and remove the abilit… ([#1121](https://github.com/windmill-labs/windmill/issues/1121)) ([3c483f5](https://github.com/windmill-labs/windmill/commit/3c483f533759b9b4e589055dbddb31f294bea8fa))
|
||||
* **frontend:** Show app builder header always on top ([#1118](https://github.com/windmill-labs/windmill/issues/1118)) ([631a3da](https://github.com/windmill-labs/windmill/commit/631a3da17f05a3d29defdf96a50d7e96a9f8baad))
|
||||
* **frontend:** Update app scripts pane ([#1146](https://github.com/windmill-labs/windmill/issues/1146)) ([18f30c8](https://github.com/windmill-labs/windmill/commit/18f30c8286f8240158643ade8b0ef4607a80fbb0))
|
||||
* **frontend:** Use absolute path on connect images ([#1095](https://github.com/windmill-labs/windmill/issues/1095)) ([43e069e](https://github.com/windmill-labs/windmill/commit/43e069eb96c0af7d3a1fe1db4f4b69f8e31e7438))
|
||||
* improvements for error handling as first step of flow ([b77c239](https://github.com/windmill-labs/windmill/commit/b77c239f307a37777acb083b0cdb5c0d214a9dd8))
|
||||
|
||||
## [1.60.0](https://github.com/windmill-labs/windmill/compare/v1.59.0...v1.60.0) (2023-01-11)
|
||||
|
||||
|
||||
|
||||
@@ -308,9 +308,7 @@ upcoming CLI tool.
|
||||
| QUEUE_LIMIT_WAIT_RESULT | None | The number of max jobs in the queue before rejecting immediately the request in 'run_wait_result' endpoint. Takes precedence on the query arg. If none is specified, there are no limit. | Worker |
|
||||
| DENO_AUTH_TOKENS | None | Custom DENO_AUTH_TOKENS to pass to worker to allow the use of private modules | Worker |
|
||||
| DENO_FLAGS | None | Override the flags passed to deno (default --allow-all) to tighten permissions. Minimum permissions needed are "--allow-read=args.json --allow-write=result.json" | Worker |
|
||||
| PIP_LOCAL_DEPENDENCIES | None | Specify dependencies that are installed locally and do not need to be solved nor installed again |
|
||||
| ADDITIONAL_PYTHON_PATHS | None | Specify python paths (separated by a :) to be appended to the PYTHONPATH of the python jobs. To be used with PIP_LOCAL_DEPENDENCIES to use python codebases within Windmill | Worker |
|
||||
| INCLUDE_HEADERS | None | Whitelist of headers that are passed to jobs as args (separated by a comma) | Server |
|
||||
| |
|
||||
|
||||
|
||||
|
||||
|
||||
373
backend/Cargo.lock
generated
373
backend/Cargo.lock
generated
@@ -135,9 +135,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.2"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b015a331cc64ebd1774ba119538573603427eaace0a1950c423ab971f903796"
|
||||
checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -180,9 +180,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.64"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
|
||||
checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -217,9 +217,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.6.4"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5694b64066a2459918d8074c2ce0d5a88f409431994c2356617c8ae0c4721fc"
|
||||
checksum = "1304eab461cf02bd70b083ed8273388f9724c549b316ba3d1e213ce0e9e7fb7e"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
@@ -251,9 +251,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.3.2"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34"
|
||||
checksum = "f487e40dc9daee24d8a1779df88522f159a54a980f99cfbe43db0be0bd3444a8"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
@@ -384,21 +384,11 @@ dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9c056b9ed43aee5e064b683aa1ec783e19c6acec7559e3ae931b7490472fbe"
|
||||
dependencies = [
|
||||
"cargo-lock",
|
||||
"git2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
version = "3.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@@ -412,26 +402,11 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||
|
||||
[[package]]
|
||||
name = "cargo-lock"
|
||||
version = "8.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996"
|
||||
dependencies = [
|
||||
"semver 1.0.16",
|
||||
"serde",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -466,9 +441,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.4"
|
||||
version = "4.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
||||
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
@@ -591,9 +566,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.0.1"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
|
||||
checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
@@ -661,9 +636,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.88"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322296e2f2e5af4270b54df9e85a02ff037e271af20ba3e7fe1575515dc840b8"
|
||||
checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
@@ -673,9 +648,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.88"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "017a1385b05d631e7875b1f151c9f012d37b53491e2a87f65bff5c262b2111d8"
|
||||
checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
@@ -688,15 +663,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.88"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c26bbb078acf09bc1ecda02d4223f03bdd28bd4874edcb0379138efc499ce971"
|
||||
checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.88"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357f40d1f06a24b60ae1fe122542c1fb05d28d32acb2aed064e84bc2ad1e252e"
|
||||
checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -910,9 +885,9 @@ checksum = "131726693bce13b09331bee70734fe266666332b6ddfef23e9dca5b8bf6dea66"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -1055,9 +1030,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
|
||||
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1070,9 +1045,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
|
||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -1080,15 +1055,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
|
||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
|
||||
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -1108,9 +1083,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
|
||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@@ -1129,9 +1104,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
|
||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1140,21 +1115,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
|
||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
|
||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.26"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
|
||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1231,19 +1206,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.15"
|
||||
@@ -1592,15 +1554,6 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.60"
|
||||
@@ -1745,36 +1698,12 @@ version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.14.2+1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
@@ -1944,15 +1873,6 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom8"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@@ -1994,9 +1914,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.3"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
||||
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
@@ -2045,18 +1965,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.9"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b"
|
||||
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.9"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
|
||||
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
@@ -2232,9 +2152,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.5.4"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f"
|
||||
checksum = "4257b4a04d91f7e9e6290be5d3da4804dd5784fafde3a497d73eb2b4a158c30a"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
@@ -2250,6 +2170,15 @@ dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
|
||||
dependencies = [
|
||||
"phf_shared 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.1"
|
||||
@@ -2262,12 +2191,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.11.1"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
|
||||
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
|
||||
dependencies = [
|
||||
"phf_generator 0.11.1",
|
||||
"phf_shared 0.11.1",
|
||||
"phf_generator 0.10.0",
|
||||
"phf_shared 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2412,12 +2341,13 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
|
||||
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"toml_edit",
|
||||
"thiserror",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2452,9 +2382,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.50"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2462,16 +2392,14 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "progenitor"
|
||||
version = "0.2.1-dev"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#8a09b98645276ef3738d3e904e1c32e5de1d657e"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#46d2df0e2a3dcbaea70669df6afb75ae27dea348"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"built",
|
||||
"clap",
|
||||
"openapiv3",
|
||||
"progenitor-client",
|
||||
"progenitor-impl",
|
||||
"progenitor-macro",
|
||||
"project-root",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
@@ -2480,7 +2408,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "progenitor-client"
|
||||
version = "0.2.1-dev"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#8a09b98645276ef3738d3e904e1c32e5de1d657e"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#46d2df0e2a3dcbaea70669df6afb75ae27dea348"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -2494,7 +2422,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "progenitor-impl"
|
||||
version = "0.2.1-dev"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#8a09b98645276ef3738d3e904e1c32e5de1d657e"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#46d2df0e2a3dcbaea70669df6afb75ae27dea348"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
"heck",
|
||||
@@ -2516,7 +2444,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "progenitor-macro"
|
||||
version = "0.2.1-dev"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#8a09b98645276ef3738d3e904e1c32e5de1d657e"
|
||||
source = "git+https://github.com/oxidecomputer/progenitor#46d2df0e2a3dcbaea70669df6afb75ae27dea348"
|
||||
dependencies = [
|
||||
"openapiv3",
|
||||
"proc-macro2",
|
||||
@@ -2530,12 +2458,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project-root"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bccbff07d5ed689c4087d20d7307a52ab6141edeedf487c3876a55b86cf63df"
|
||||
|
||||
[[package]]
|
||||
name = "prometheus"
|
||||
version = "0.13.3"
|
||||
@@ -2696,11 +2618,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.14"
|
||||
version = "0.11.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
|
||||
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"base64 0.13.1",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@@ -2728,7 +2650,6 @@ dependencies = [
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
]
|
||||
@@ -2854,9 +2775,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.7"
|
||||
version = "0.36.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
||||
checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@@ -2890,7 +2811,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython#b6e447145800ec7888f035bf266329e4b457e5f9"
|
||||
source = "git+https://github.com/RustPython/RustPython#59b191c789c891a500659d2c3b29a645883f780a"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-compiler-core",
|
||||
@@ -2899,7 +2820,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython#b6e447145800ec7888f035bf266329e4b457e5f9"
|
||||
source = "git+https://github.com/RustPython/RustPython#59b191c789c891a500659d2c3b29a645883f780a"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2916,7 +2837,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython#b6e447145800ec7888f035bf266329e4b457e5f9"
|
||||
source = "git+https://github.com/RustPython/RustPython#59b191c789c891a500659d2c3b29a645883f780a"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -2926,7 +2847,7 @@ dependencies = [
|
||||
"log",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"phf",
|
||||
"phf 0.10.1",
|
||||
"phf_codegen",
|
||||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
@@ -3024,9 +2945,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
||||
checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
@@ -3037,9 +2958,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.8.0"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
||||
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -3068,9 +2989,6 @@ name = "semver"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
@@ -3220,9 +3138,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.17"
|
||||
version = "0.9.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567"
|
||||
checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
@@ -3571,9 +3489,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "swc_atoms"
|
||||
version = "0.4.34"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "731cf66bd8e11030f056f91f9d8af77f83ec4377ff04d1670778a57d1607402a"
|
||||
checksum = "93a49e93996e1c1cfdb641cd94888da545d440ff6cada04155ef118adee620c1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
@@ -3585,9 +3503,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_common"
|
||||
version = "0.29.29"
|
||||
version = "0.29.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97e491d31418cd33fea58e9f893316fc04b30e2b5d0e750c066e2ba4907ae54"
|
||||
checksum = "90a2c285d33b47a5e532a662c178dc91956534ff52207892918d3034a534ae12"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ast_node",
|
||||
@@ -3612,9 +3530,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_ast"
|
||||
version = "0.96.3"
|
||||
version = "0.96.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a887102d5595b557261aa4bde35f3d71906fba674d4b79cd5c59b4155b12ee2d"
|
||||
checksum = "708345b44bedd33ff5dedfc66263070af0cad788d4bb19b51007b4583a64c43f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"is-macro",
|
||||
@@ -3629,9 +3547,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_ecma_parser"
|
||||
version = "0.124.5"
|
||||
version = "0.124.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e75888eabf1ad8a8968e3befc7cd20c10e4721254d3344285bd5c3a42f58dc1"
|
||||
checksum = "1ec6b89544ad2242a8e19d966a6c3ac8e6eb5ec5060e08bdcb01062c479b41ca"
|
||||
dependencies = [
|
||||
"either",
|
||||
"enum_kind",
|
||||
@@ -3672,9 +3590,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_visit"
|
||||
version = "0.5.4"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "470a1963cf182fdcbbac46e3a7fd2caf7329da0e568d3668202da9501c880e16"
|
||||
checksum = "82f2bcb7223e185c4c7cbf5e0c1207dec6d2bfd5e72e3fb7b3e8d179747e9130"
|
||||
dependencies = [
|
||||
"either",
|
||||
"swc_visit_macros",
|
||||
@@ -3682,9 +3600,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "swc_visit_macros"
|
||||
version = "0.5.5"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6098b717cfd4c85f5cddec734af191dbce461c39975ed567c32ac6d0c6d61a6d"
|
||||
checksum = "8fb1f3561674d84947694d41fb6d5737d19539222779baeac1b3a071a2b29428"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"pmutil",
|
||||
@@ -3849,9 +3767,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.25.0"
|
||||
version = "1.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
|
||||
checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
@@ -3953,30 +3871,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"toml_datetime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toolchain_find"
|
||||
version = "0.2.0"
|
||||
@@ -4172,7 +4073,7 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
[[package]]
|
||||
name = "typify"
|
||||
version = "0.0.11-dev"
|
||||
source = "git+https://github.com/oxidecomputer/typify#cd1f95b66b0d0fbb33537d66043f26512ee3268b"
|
||||
source = "git+https://github.com/oxidecomputer/typify#0f173877fa12c7e53c351fd1084e7cab0c6a7be1"
|
||||
dependencies = [
|
||||
"typify-impl",
|
||||
"typify-macro",
|
||||
@@ -4181,7 +4082,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "typify-impl"
|
||||
version = "0.0.11-dev"
|
||||
source = "git+https://github.com/oxidecomputer/typify#cd1f95b66b0d0fbb33537d66043f26512ee3268b"
|
||||
source = "git+https://github.com/oxidecomputer/typify#0f173877fa12c7e53c351fd1084e7cab0c6a7be1"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"log",
|
||||
@@ -4199,7 +4100,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "typify-macro"
|
||||
version = "0.0.11-dev"
|
||||
source = "git+https://github.com/oxidecomputer/typify#cd1f95b66b0d0fbb33537d66043f26512ee3268b"
|
||||
source = "git+https://github.com/oxidecomputer/typify#0f173877fa12c7e53c351fd1084e7cab0c6a7be1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4290,9 +4191,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.10"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
|
||||
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-general-category"
|
||||
@@ -4323,9 +4224,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
@@ -4542,19 +4443,6 @@ version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.60"
|
||||
@@ -4586,9 +4474,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.0"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
|
||||
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"libc",
|
||||
@@ -4638,7 +4526,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -4665,7 +4553,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -4685,6 +4573,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"magic-crypt",
|
||||
"mime_guess",
|
||||
"prometheus",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"retainer",
|
||||
@@ -4718,7 +4607,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"chrono",
|
||||
@@ -4733,7 +4622,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
@@ -4746,7 +4635,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -4770,7 +4659,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4778,12 +4667,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"phf",
|
||||
"phf 0.11.1",
|
||||
"regex",
|
||||
"unicode-general-category",
|
||||
"windmill-common",
|
||||
@@ -4792,11 +4681,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"phf",
|
||||
"phf 0.11.1",
|
||||
"unicode-general-category",
|
||||
"windmill-common",
|
||||
"windmill-parser",
|
||||
@@ -4804,12 +4693,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"phf",
|
||||
"phf 0.11.1",
|
||||
"regex",
|
||||
"rustpython-parser",
|
||||
"serde_json",
|
||||
@@ -4819,7 +4708,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deno_core",
|
||||
@@ -4833,7 +4722,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -4856,7 +4745,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -19,7 +19,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -83,7 +83,7 @@ chrono = { version = "^0", features = ["serde"] }
|
||||
tracing = "^0"
|
||||
tracing-subscriber = { version = "^0", features = ["env-filter", "json"] }
|
||||
prometheus = { version = "^0", default-features = false }
|
||||
cookie = { version = "0.16.2" }
|
||||
cookie = { version = "^0" }
|
||||
phf = { version = "0.11", features = ["macros"] }
|
||||
rust-embed = "^6"
|
||||
mime_guess = "^2"
|
||||
|
||||
5
backend/migrations/20230126023323_webhook.up.sql
Normal file
5
backend/migrations/20230126023323_webhook.up.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- Add up migration script here
|
||||
ALTER TABLE
|
||||
workspace_settings
|
||||
ADD
|
||||
COLUMN webhook text;
|
||||
@@ -1,2 +0,0 @@
|
||||
-- Add up migration script here
|
||||
ALTER TABLE account ALTER COLUMN refresh_token TYPE VARCHAR(1500);
|
||||
@@ -1 +0,0 @@
|
||||
-- Add down migration script here
|
||||
@@ -1,4 +0,0 @@
|
||||
-- Add up migration script here
|
||||
|
||||
GRANT ALL PRIVILEGES ON TABLE favorite TO windmill_admin;
|
||||
GRANT ALL PRIVILEGES ON TABLE favorite TO windmill_user;
|
||||
@@ -1 +0,0 @@
|
||||
-- Add down migration script here
|
||||
@@ -1,25 +0,0 @@
|
||||
-- Add up migration script here
|
||||
|
||||
|
||||
CREATE POLICY see_folder_extra_perms_user ON capture FOR ALL
|
||||
USING (SPLIT_PART(capture.path, '/', 1) = 'f' AND SPLIT_PART(capture.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]))
|
||||
WITH CHECK (SPLIT_PART(capture.path, '/', 1) = 'f' AND SPLIT_PART(capture.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
|
||||
|
||||
DO
|
||||
$do$
|
||||
DECLARE
|
||||
i text;
|
||||
arr text[] := array['queue', 'completed_job'];
|
||||
BEGIN
|
||||
FOREACH i IN ARRAY arr
|
||||
LOOP
|
||||
EXECUTE FORMAT(
|
||||
$$
|
||||
CREATE POLICY see_folder_extra_perms_user ON %1$I FOR ALL
|
||||
USING (%1$I.visible_to_owner IS true AND SPLIT_PART(%1$I.script_path, '/', 1) = 'f' AND SPLIT_PART(%1$I.script_path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]));
|
||||
$$,
|
||||
i
|
||||
);
|
||||
END LOOP;
|
||||
END
|
||||
$do$;
|
||||
@@ -1 +0,0 @@
|
||||
-- Add down migration script here
|
||||
@@ -1,5 +0,0 @@
|
||||
-- Add up migration script here
|
||||
|
||||
CREATE POLICY see_folder_extra_perms_user ON account FOR ALL
|
||||
USING (SPLIT_PART(account.owner, '/', 1) = 'f' AND SPLIT_PART(account.owner, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]))
|
||||
WITH CHECK (SPLIT_PART(account.owner, '/', 1) = 'f' AND SPLIT_PART(account.owner, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
|
||||
@@ -80,7 +80,7 @@ pub fn parse_python_signature(code: &str) -> error::Result<MainArgSignature> {
|
||||
let def_arg_start = params.args.len() - params.defaults.len();
|
||||
Ok(MainArgSignature {
|
||||
star_args: params.vararg.is_some(),
|
||||
star_kwargs: params.kwarg.is_some(),
|
||||
star_kwargs: params.vararg.is_some(),
|
||||
args: params
|
||||
.args
|
||||
.into_iter()
|
||||
@@ -136,10 +136,7 @@ fn to_value(et: &ExprKind) -> Option<serde_json::Value> {
|
||||
.into_iter()
|
||||
.zip(values)
|
||||
.map(|(k, v)| {
|
||||
let key = k
|
||||
.as_ref()
|
||||
.map(|x| x.node.clone())
|
||||
.and_then(|n| to_value(&n))
|
||||
let key = to_value(&k.node)
|
||||
.and_then(|x| match x {
|
||||
serde_json::Value::String(s) => Some(s),
|
||||
_ => None,
|
||||
@@ -185,7 +182,6 @@ static PYTHON_IMPORTS_REPLACEMENT: phf::Map<&'static str, &'static str> = phf_ma
|
||||
"f" => "requests",
|
||||
"shopify" => "ShopifyAPI",
|
||||
"seleniumwire" => "selenium-wire",
|
||||
"openbb-terminal" => "openbb[all]",
|
||||
};
|
||||
|
||||
fn replace_import(x: String) -> String {
|
||||
@@ -197,13 +193,13 @@ fn replace_import(x: String) -> String {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r"^\#\s?(\S+)$").unwrap();
|
||||
static ref RE: Regex = Regex::new(r"^\#(\S+)$").unwrap();
|
||||
}
|
||||
|
||||
pub fn parse_python_imports(code: &str) -> error::Result<Vec<String>> {
|
||||
let find_requirements = code
|
||||
.lines()
|
||||
.find_position(|x| x.starts_with("#requirements:") || x.starts_with("# requirements:"));
|
||||
.find_position(|x| x.starts_with("#requirements:"));
|
||||
if let Some((pos, _)) = find_requirements {
|
||||
let lines = code
|
||||
.lines()
|
||||
|
||||
@@ -558,6 +558,11 @@
|
||||
"name": "plan",
|
||||
"ordinal": 8,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "webhook",
|
||||
"ordinal": 9,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
@@ -569,6 +574,7 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
],
|
||||
"parameters": {
|
||||
@@ -1231,6 +1237,18 @@
|
||||
},
|
||||
"query": "INSERT INTO usr\n (workspace_id, email, username, is_admin, operator)\n VALUES ($1, $2, $3, $4, $5)"
|
||||
},
|
||||
"33d69b3915ddfde40323ace65c14e39fa4bbc8b5dd50a34e165765eaea1f4966": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "UPDATE workspace_settings SET webhook = NULL WHERE workspace_id = $1"
|
||||
},
|
||||
"355dcb2cbebd13f0e3bdd4929b9e431b0e6d72716d1c4f9ab6af6adce5b5e4b3": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
@@ -1850,6 +1868,11 @@
|
||||
"name": "plan",
|
||||
"ordinal": 8,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "webhook",
|
||||
"ordinal": 9,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
@@ -1861,6 +1884,7 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
],
|
||||
"parameters": {
|
||||
@@ -2710,6 +2734,19 @@
|
||||
},
|
||||
"query": "UPDATE script SET archived = true WHERE path = $1 AND workspace_id = $2 RETURNING hash"
|
||||
},
|
||||
"8292b7b2cce5319575bc09ad18f29b63270872b6e5c6df1f0a326370058f13b0": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "UPDATE workspace_settings SET webhook = $1 WHERE workspace_id = $2"
|
||||
},
|
||||
"82f3c4cd1c1f6aea86d66f675442587684391bc32be9ab55ae20aab549b7bba5": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -3765,6 +3802,26 @@
|
||||
},
|
||||
"query": "SELECT email FROM usr where username = $1 AND workspace_id = $2"
|
||||
},
|
||||
"a34b79872766941cae2d62c99d80e28b7214dd2fcbb68020a63325bbcb34f417": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "webhook",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
true
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "SELECT webhook FROM workspace_settings WHERE workspace_id = $1"
|
||||
},
|
||||
"a38059dc3574da498ce986c916b6d385b1f18d5bd659ef13c43fafa9daff6bda": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
|
||||
@@ -70,4 +70,5 @@ cookie.workspace = true
|
||||
sha2.workspace = true
|
||||
urlencoding.workspace = true
|
||||
async-stripe.workspace = true
|
||||
lazy_static.workspace = true
|
||||
lazy_static.workspace = true
|
||||
prometheus.workspace = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.61.1
|
||||
version: 1.60.0
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
@@ -883,6 +883,8 @@ paths:
|
||||
type: string
|
||||
customer_id:
|
||||
type: string
|
||||
webhook:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/workspaces/premium_info:
|
||||
get:
|
||||
@@ -962,6 +964,33 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/workspaces/edit_webhook:
|
||||
post:
|
||||
summary: edit webhook
|
||||
operationId: editWebhook
|
||||
tags:
|
||||
- workspace
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
requestBody:
|
||||
description: WorkspaceWebhook
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
webhook:
|
||||
type: string
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: status
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/users/list:
|
||||
get:
|
||||
summary: list users
|
||||
@@ -2445,44 +2474,6 @@ paths:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/w/{workspace}/jobs/run_wait_result/f/{path}:
|
||||
post:
|
||||
summary: run flow by path and wait until completion
|
||||
operationId: runWaitResultFlowByPath
|
||||
tags:
|
||||
- job
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
- name: scheduled_for
|
||||
description: when to schedule this job (leave empty for immediate run)
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
- name: scheduled_in_secs
|
||||
description: schedule the script to execute in the number of seconds starting now
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- $ref: "#/components/parameters/IncludeHeader"
|
||||
- $ref: "#/components/parameters/QueueLimit"
|
||||
|
||||
requestBody:
|
||||
description: script args
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ScriptArgs"
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: job result
|
||||
content:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/w/{workspace}/jobs/result_by_id/{flow_job_id}/{node_id}:
|
||||
get:
|
||||
summary: get job result by id
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::{
|
||||
jobs::script_path_to_payload,
|
||||
users::{require_owner_of_path, Authed, OptAuthed},
|
||||
variables::build_crypt,
|
||||
webhook_util::{WebhookMessage, WebhookUtil},
|
||||
};
|
||||
use axum::{
|
||||
extract::{Extension, Json, Path, Query},
|
||||
@@ -310,6 +311,7 @@ async fn get_secret_id(
|
||||
async fn create_app(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path(w_id): Path<String>,
|
||||
Json(app): Json<CreateApp>,
|
||||
) -> Result<(StatusCode, String)> {
|
||||
@@ -356,7 +358,12 @@ async fn create_app(
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::CreateApp {
|
||||
workspace: w_id.clone(),
|
||||
path: app.path.clone(),
|
||||
});
|
||||
|
||||
Ok((StatusCode::CREATED, app.path))
|
||||
}
|
||||
@@ -395,6 +402,7 @@ pub async fn get_hub_app_by_id(
|
||||
async fn delete_app(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> Result<String> {
|
||||
let path = path.to_path();
|
||||
@@ -418,6 +426,8 @@ async fn delete_app(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook
|
||||
.send_message(WebhookMessage::DeleteApp { workspace: w_id.clone(), path: path.to_owned() });
|
||||
|
||||
Ok(format!("app {} deleted", path))
|
||||
}
|
||||
@@ -425,6 +435,7 @@ async fn delete_app(
|
||||
async fn update_app(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
Json(ns): Json<EditApp>,
|
||||
@@ -514,6 +525,11 @@ async fn update_app(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::UpdateApp {
|
||||
workspace: w_id.clone(),
|
||||
old_path: path.to_owned(),
|
||||
new_path: npath.clone(),
|
||||
});
|
||||
|
||||
Ok(format!("app {} updated (npath: {:?})", path, npath))
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ use crate::{
|
||||
db::{UserDB, DB},
|
||||
schedule::clear_schedule,
|
||||
users::{require_owner_of_path, Authed},
|
||||
webhook_util::{WebhookMessage, WebhookUtil},
|
||||
};
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
@@ -181,6 +182,7 @@ async fn check_path_conflict<'c>(
|
||||
async fn create_flow(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path(w_id): Path<String>,
|
||||
Json(nf): Json<NewFlow>,
|
||||
) -> Result<(StatusCode, String)> {
|
||||
@@ -221,6 +223,10 @@ async fn create_flow(
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::CreateFlow {
|
||||
workspace: w_id.clone(),
|
||||
path: nf.path.clone(),
|
||||
});
|
||||
|
||||
let tx = user_db.begin(&authed).await?;
|
||||
let (dependency_job_uuid, mut tx) = push(
|
||||
@@ -280,6 +286,7 @@ async fn update_flow(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Extension(db): Extension<DB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, flow_path)): Path<(String, StripPath)>,
|
||||
Json(nf): Json<NewFlow>,
|
||||
) -> Result<String> {
|
||||
@@ -368,6 +375,11 @@ async fn update_flow(
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::UpdateFlow {
|
||||
workspace: w_id.clone(),
|
||||
old_path: flow_path.to_owned(),
|
||||
new_path: nf.path.clone(),
|
||||
});
|
||||
|
||||
let tx = user_db.begin(&authed).await?;
|
||||
let (dependency_job_uuid, mut tx) = push(
|
||||
@@ -450,6 +462,7 @@ async fn exists_flow_by_path(
|
||||
async fn archive_flow_by_path(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> Result<String> {
|
||||
let path = path.to_path();
|
||||
@@ -474,6 +487,10 @@ async fn archive_flow_by_path(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::ArchiveFlow {
|
||||
workspace: w_id.clone(),
|
||||
path: path.to_owned(),
|
||||
});
|
||||
|
||||
Ok(format!("Flow {path} archived"))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
use crate::{
|
||||
db::{UserDB, DB},
|
||||
users::Authed,
|
||||
webhook_util::{WebhookMessage, WebhookUtil},
|
||||
};
|
||||
use axum::{
|
||||
extract::{Extension, Path, Query},
|
||||
@@ -139,6 +140,7 @@ async fn check_name_conflict<'c>(
|
||||
async fn create_folder(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path(w_id): Path<String>,
|
||||
Json(ng): Json<NewFolder>,
|
||||
) -> Result<String> {
|
||||
@@ -193,8 +195,12 @@ async fn create_folder(
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::CreateFolder {
|
||||
workspace: w_id.clone(),
|
||||
name: ng.name.clone(),
|
||||
});
|
||||
|
||||
Ok(format!("Created folder {}", ng.name))
|
||||
}
|
||||
|
||||
@@ -245,6 +251,7 @@ pub async fn require_is_owner(
|
||||
async fn update_folder(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
Json(ng): Json<UpdateFolder>,
|
||||
) -> Result<String> {
|
||||
@@ -298,8 +305,12 @@ async fn update_folder(
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::UpdateFolder {
|
||||
workspace: w_id.clone(),
|
||||
name: name.to_owned(),
|
||||
});
|
||||
|
||||
Ok(format!("Updated folder {}", name))
|
||||
}
|
||||
|
||||
@@ -416,6 +427,7 @@ async fn get_folder_usage(
|
||||
async fn delete_folder(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
) -> Result<String> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
@@ -440,6 +452,10 @@ async fn delete_folder(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook
|
||||
.send_message(WebhookMessage::DeleteFolder { workspace: w_id.clone(), name: name.clone() });
|
||||
|
||||
Ok(format!("delete folder at name {}", name))
|
||||
}
|
||||
|
||||
@@ -447,6 +463,7 @@ async fn add_owner(
|
||||
authed: Authed,
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
Json(Owner { owner }): Json<Owner>,
|
||||
) -> Result<String> {
|
||||
@@ -477,6 +494,10 @@ async fn add_owner(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook
|
||||
.send_message(WebhookMessage::UpdateFolder { workspace: w_id.clone(), name: name.clone() });
|
||||
|
||||
Ok(format!("Added {} to folder {}", owner, name))
|
||||
}
|
||||
|
||||
@@ -510,6 +531,7 @@ async fn remove_owner(
|
||||
authed: Authed,
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
Json(Owner { owner }): Json<Owner>,
|
||||
) -> Result<String> {
|
||||
@@ -540,5 +562,9 @@ async fn remove_owner(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook
|
||||
.send_message(WebhookMessage::UpdateFolder { workspace: w_id.clone(), name: name.clone() });
|
||||
|
||||
Ok(format!("Removed {} to folder {}", owner, name))
|
||||
}
|
||||
|
||||
@@ -53,10 +53,6 @@ pub fn workspaced_service() -> Router {
|
||||
"/run_wait_result/h/:hash",
|
||||
post(run_wait_result_job_by_hash),
|
||||
)
|
||||
.route(
|
||||
"/run_wait_result/f/*script_path",
|
||||
post(run_wait_result_flow_by_path),
|
||||
)
|
||||
.route("/run/h/:hash", post(run_job_by_hash))
|
||||
.route("/run/preview", post(run_preview_job))
|
||||
.route("/run/preview_flow", post(run_preview_flow_job))
|
||||
@@ -107,7 +103,9 @@ async fn get_result_by_id(
|
||||
Query(ResultByIdQuery { skip_direct }): Query<ResultByIdQuery>,
|
||||
Path((w_id, flow_id, node_id)): Path<(String, String, String)>,
|
||||
) -> windmill_common::error::JsonResult<serde_json::Value> {
|
||||
tracing::error!("get_result_by_id_bef: {:?} {:?}", flow_id, node_id);
|
||||
let res = windmill_queue::get_result_by_id(db, skip_direct, w_id, flow_id, node_id).await?;
|
||||
tracing::error!("get_result_by_id: {:?}", res);
|
||||
Ok(Json(res))
|
||||
}
|
||||
|
||||
@@ -270,14 +268,6 @@ pub struct RunJobQuery {
|
||||
queue_limit: Option<i64>,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref INCLUDE_HEADERS: Vec<String> = std::env::var("INCLUDE_HEADERS")
|
||||
.ok().map(|x| x
|
||||
.split(',')
|
||||
.map(|s| s.to_string())
|
||||
.collect()).unwrap_or_default();
|
||||
}
|
||||
|
||||
impl RunJobQuery {
|
||||
async fn get_scheduled_for<'c>(
|
||||
&self,
|
||||
@@ -298,14 +288,11 @@ impl RunJobQuery {
|
||||
headers: HeaderMap,
|
||||
mut args: serde_json::Map<String, serde_json::Value>,
|
||||
) -> serde_json::Map<String, serde_json::Value> {
|
||||
let whitelist = self
|
||||
.include_header
|
||||
self.include_header
|
||||
.as_ref()
|
||||
.map(|s| s.split(",").map(|s| s.to_string()).collect::<Vec<_>>())
|
||||
.unwrap_or_default();
|
||||
whitelist
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.chain(INCLUDE_HEADERS.iter())
|
||||
.for_each(|h| {
|
||||
if let Some(v) = headers.get(h) {
|
||||
args.insert(
|
||||
@@ -1403,53 +1390,6 @@ pub async fn run_wait_result_job_by_hash(
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn run_wait_result_flow_by_path(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(timeout): Extension<Arc<TimeoutWaitResult>>,
|
||||
Path((w_id, flow_path)): Path<(String, StripPath)>,
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
headers: HeaderMap,
|
||||
Json(args): Json<Option<serde_json::Map<String, serde_json::Value>>>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
check_queue_too_long(db, run_query.queue_limit).await?;
|
||||
|
||||
let flow_path = flow_path.to_path();
|
||||
let mut tx = user_db.clone().begin(&authed).await?;
|
||||
let scheduled_for = run_query.get_scheduled_for(&mut tx).await?;
|
||||
let args = run_query.add_include_headers(headers, args.unwrap_or_default());
|
||||
|
||||
let (uuid, tx) = push(
|
||||
tx,
|
||||
&w_id,
|
||||
JobPayload::Flow(flow_path.to_string()),
|
||||
args,
|
||||
&authed.username,
|
||||
&authed.email,
|
||||
username_to_permissioned_as(&authed.username),
|
||||
scheduled_for,
|
||||
None,
|
||||
run_query.parent_job,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
!run_query.invisible_to_owner.unwrap_or(false),
|
||||
)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
run_wait_result(
|
||||
authed,
|
||||
Extension(user_db),
|
||||
timeout.0,
|
||||
uuid,
|
||||
Path((w_id, flow_path)),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
// a similar function exists on the worker
|
||||
pub async fn script_path_to_payload<'c>(
|
||||
script_path: &str,
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::{
|
||||
oauth2::{build_oauth_clients, SlackVerifier},
|
||||
tracing_init::{MyMakeSpan, MyOnResponse},
|
||||
users::{Authed, OptAuthed},
|
||||
webhook_util::{WebhookShared, WebhookUtil},
|
||||
};
|
||||
|
||||
mod apps;
|
||||
@@ -42,6 +43,7 @@ mod tracing_init;
|
||||
mod users;
|
||||
mod utils;
|
||||
mod variables;
|
||||
mod webhook_util;
|
||||
mod worker_ping;
|
||||
mod workspaces;
|
||||
|
||||
@@ -106,7 +108,8 @@ pub async fn run_server(
|
||||
std::env::var("COOKIE_DOMAIN").ok(),
|
||||
))))
|
||||
.layer(Extension(http_client))
|
||||
.layer(CookieManagerLayer::new());
|
||||
.layer(CookieManagerLayer::new())
|
||||
.layer(Extension(WebhookShared::new(rx.resubscribe())));
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
.nest(
|
||||
@@ -147,7 +150,8 @@ pub async fn run_server(
|
||||
.nest("/flows", flows::workspaced_service())
|
||||
.nest("/capture", capture::workspaced_service())
|
||||
.nest("/favorites", favorite::workspaced_service())
|
||||
.nest("/folders", folders::workspaced_service()),
|
||||
.nest("/folders", folders::workspaced_service())
|
||||
.route_layer(from_extractor::<WebhookUtil>()),
|
||||
)
|
||||
.nest("/workspaces", workspaces::global_service())
|
||||
.nest(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
use crate::{
|
||||
db::{UserDB, DB},
|
||||
users::{require_owner_of_path, Authed},
|
||||
webhook_util::{WebhookMessage, WebhookUtil},
|
||||
};
|
||||
use axum::{
|
||||
extract::{Extension, Path, Query},
|
||||
@@ -263,6 +264,7 @@ async fn check_path_conflict<'c>(
|
||||
async fn create_resource(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path(w_id): Path<String>,
|
||||
Json(resource): Json<CreateResource>,
|
||||
) -> Result<(StatusCode, String)> {
|
||||
@@ -293,6 +295,11 @@ async fn create_resource(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::CreateResource {
|
||||
workspace: w_id.clone(),
|
||||
path: resource.path.clone(),
|
||||
});
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
format!("resource {} created", resource.path),
|
||||
@@ -302,6 +309,7 @@ async fn create_resource(
|
||||
async fn delete_resource(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> Result<String> {
|
||||
let path = path.to_path();
|
||||
@@ -333,12 +341,18 @@ async fn delete_resource(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::DeleteResource {
|
||||
workspace: w_id.clone(),
|
||||
path: path.to_owned(),
|
||||
});
|
||||
|
||||
Ok(format!("resource {} deleted", path))
|
||||
}
|
||||
|
||||
async fn update_resource(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
Json(ns): Json<EditResource>,
|
||||
@@ -400,6 +414,12 @@ async fn update_resource(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::UpdateResource {
|
||||
workspace: w_id.clone(),
|
||||
old_path: path.to_owned(),
|
||||
new_path: npath.clone(),
|
||||
});
|
||||
|
||||
Ok(format!("resource {} updated (npath: {:?})", path, npath))
|
||||
}
|
||||
|
||||
@@ -411,6 +431,7 @@ struct UpdateResource {
|
||||
async fn update_resource_value(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
Json(nv): Json<UpdateResource>,
|
||||
) -> Result<String> {
|
||||
@@ -436,6 +457,11 @@ async fn update_resource_value(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::UpdateResource {
|
||||
workspace: w_id.clone(),
|
||||
old_path: path.to_owned(),
|
||||
new_path: path.to_owned(),
|
||||
});
|
||||
|
||||
Ok(format!("value of resource {} updated", path))
|
||||
}
|
||||
@@ -513,6 +539,7 @@ async fn exists_resource_type(
|
||||
async fn create_resource_type(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path(w_id): Path<String>,
|
||||
Json(resource_type): Json<CreateResourceType>,
|
||||
) -> Result<(StatusCode, String)> {
|
||||
@@ -543,6 +570,8 @@ async fn create_resource_type(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::CreateResourceType { name: resource_type.name.clone() });
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
format!("resource_type {} created", resource_type.name),
|
||||
@@ -574,6 +603,7 @@ async fn check_rt_path_conflict<'c>(
|
||||
async fn delete_resource_type(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
) -> Result<String> {
|
||||
require_admin(authed.is_admin, &authed.username)?;
|
||||
@@ -598,6 +628,7 @@ async fn delete_resource_type(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::DeleteResourceType { name: name.clone() });
|
||||
|
||||
Ok(format!("resource_type {} deleted", name))
|
||||
}
|
||||
@@ -605,6 +636,7 @@ async fn delete_resource_type(
|
||||
async fn update_resource_type(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
Json(ns): Json<EditResourceType>,
|
||||
) -> Result<String> {
|
||||
@@ -634,6 +666,7 @@ async fn update_resource_type(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::UpdateResourceType { name: name.clone() });
|
||||
|
||||
Ok(format!("resource_type {} updated", name))
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
db::{UserDB, DB},
|
||||
schedule::clear_schedule,
|
||||
users::{require_owner_of_path, Authed},
|
||||
webhook_util::{WebhookMessage, WebhookUtil},
|
||||
};
|
||||
use axum::{
|
||||
extract::{Extension, Path, Query},
|
||||
@@ -184,6 +185,7 @@ fn hash_script(ns: &NewScript) -> i64 {
|
||||
async fn create_script(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Extension(db): Extension<DB>,
|
||||
Path(w_id): Path<String>,
|
||||
Json(ns): Json<NewScript>,
|
||||
@@ -400,6 +402,11 @@ async fn create_script(
|
||||
Some([("hash", hash.to_string().as_str())].into()),
|
||||
)
|
||||
.await?;
|
||||
webhook.send_message(WebhookMessage::UpdateScript {
|
||||
workspace: w_id.clone(),
|
||||
path: ns.path.clone(),
|
||||
hash: hash.to_string(),
|
||||
});
|
||||
} else {
|
||||
audit_log(
|
||||
&mut tx,
|
||||
@@ -417,6 +424,11 @@ async fn create_script(
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
webhook.send_message(WebhookMessage::CreateScript {
|
||||
workspace: w_id.clone(),
|
||||
path: ns.path.clone(),
|
||||
hash: hash.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
tx.commit().await?;
|
||||
@@ -600,6 +612,7 @@ async fn get_deployment_status(
|
||||
|
||||
async fn archive_script_by_path(
|
||||
authed: Authed,
|
||||
webhook: WebhookUtil,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
@@ -626,6 +639,10 @@ async fn archive_script_by_path(
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
webhook.send_message(WebhookMessage::DeleteScript {
|
||||
workspace: w_id.clone(),
|
||||
hash: hash.to_string(),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -633,6 +650,7 @@ async fn archive_script_by_path(
|
||||
async fn archive_script_by_hash(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, hash)): Path<(String, ScriptHash)>,
|
||||
) -> JsonResult<Script> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
@@ -657,12 +675,18 @@ async fn archive_script_by_hash(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::DeleteScript {
|
||||
workspace: w_id.clone(),
|
||||
hash: hash.to_string(),
|
||||
});
|
||||
|
||||
Ok(Json(script))
|
||||
}
|
||||
|
||||
async fn delete_script_by_hash(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, hash)): Path<(String, ScriptHash)>,
|
||||
) -> JsonResult<Script> {
|
||||
@@ -691,6 +715,11 @@ async fn delete_script_by_hash(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::DeleteScript {
|
||||
workspace: w_id.clone(),
|
||||
hash: hash.to_string(),
|
||||
});
|
||||
|
||||
Ok(Json(script))
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::{
|
||||
db::{UserDB, DB},
|
||||
oauth2::{AllClients, _refresh_token},
|
||||
users::{require_owner_of_path, Authed},
|
||||
webhook_util::{WebhookMessage, WebhookUtil},
|
||||
BaseUrl,
|
||||
};
|
||||
/*
|
||||
@@ -224,6 +225,7 @@ async fn check_path_conflict<'c>(
|
||||
async fn create_variable(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path(w_id): Path<String>,
|
||||
Json(variable): Json<CreateVariable>,
|
||||
) -> Result<(StatusCode, String)> {
|
||||
@@ -265,6 +267,11 @@ async fn create_variable(
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::CreateVariable {
|
||||
workspace: w_id.clone(),
|
||||
path: variable.path.clone(),
|
||||
});
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
format!("variable {} created", variable.path),
|
||||
@@ -274,6 +281,7 @@ async fn create_variable(
|
||||
async fn delete_variable(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> Result<String> {
|
||||
let path = path.to_path();
|
||||
@@ -306,6 +314,11 @@ async fn delete_variable(
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::DeleteVariable {
|
||||
workspace: w_id.clone(),
|
||||
path: path.to_owned(),
|
||||
});
|
||||
|
||||
Ok(format!("variable {} deleted", path))
|
||||
}
|
||||
|
||||
@@ -320,6 +333,7 @@ struct EditVariable {
|
||||
async fn update_variable(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
webhook: WebhookUtil,
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
Json(ns): Json<EditVariable>,
|
||||
@@ -405,6 +419,12 @@ async fn update_variable(
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
webhook.send_message(WebhookMessage::UpdateVariable {
|
||||
workspace: w_id.clone(),
|
||||
old_path: path.to_owned(),
|
||||
new_path: npath.clone(),
|
||||
});
|
||||
|
||||
Ok(format!("variable {} updated (npath: {:?})", path, npath))
|
||||
}
|
||||
|
||||
|
||||
156
backend/windmill-api/src/webhook_util.rs
Normal file
156
backend/windmill-api/src/webhook_util.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use axum::{
|
||||
async_trait,
|
||||
extract::{FromRequestParts, OriginalUri},
|
||||
http::request::Parts,
|
||||
Extension,
|
||||
};
|
||||
use hyper::StatusCode;
|
||||
use serde::Serialize;
|
||||
use tokio::{select, sync::mpsc};
|
||||
|
||||
use crate::db::DB;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
// TODO: these aren't synced, they should be moved into the queue abstraction once/if that happens.
|
||||
static ref WEBHOOK_REQUEST_COUNT: prometheus::Histogram = prometheus::register_histogram!(
|
||||
"webhook_request",
|
||||
"Histogram of webhook requests made"
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum WebhookMessage {
|
||||
// See https://serde.rs/enum-representations.html#internally-tagged for how this looks in JSON
|
||||
CreateApp { workspace: String, path: String },
|
||||
DeleteApp { workspace: String, path: String },
|
||||
UpdateApp { workspace: String, old_path: String, new_path: String },
|
||||
CreateFlow { workspace: String, path: String },
|
||||
UpdateFlow { workspace: String, old_path: String, new_path: String },
|
||||
ArchiveFlow { workspace: String, path: String },
|
||||
CreateFolder { workspace: String, name: String },
|
||||
UpdateFolder { workspace: String, name: String },
|
||||
DeleteFolder { workspace: String, name: String },
|
||||
DeleteResource { workspace: String, path: String },
|
||||
CreateResource { workspace: String, path: String },
|
||||
UpdateResource { workspace: String, old_path: String, new_path: String },
|
||||
CreateResourceType { name: String },
|
||||
DeleteResourceType { name: String },
|
||||
UpdateResourceType { name: String },
|
||||
CreateScript { workspace: String, path: String, hash: String },
|
||||
UpdateScript { workspace: String, path: String, hash: String },
|
||||
DeleteScript { workspace: String, hash: String },
|
||||
CreateVariable { workspace: String, path: String },
|
||||
UpdateVariable { workspace: String, old_path: String, new_path: String },
|
||||
DeleteVariable { workspace: String, path: String },
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WebhookShared {
|
||||
pub channel: mpsc::UnboundedSender<(String, WebhookMessage)>,
|
||||
}
|
||||
|
||||
impl WebhookShared {
|
||||
pub fn new(mut shutdown_rx: tokio::sync::broadcast::Receiver<()>) -> Self {
|
||||
let (tx, mut rx) = mpsc::unbounded_channel::<(String, WebhookMessage)>();
|
||||
let _process = tokio::spawn(async move {
|
||||
let client = reqwest::Client::builder()
|
||||
// TODO: investigate pool timeouts and such if TCP load is high
|
||||
.timeout(Duration::from_secs(5))
|
||||
.build()
|
||||
.unwrap();
|
||||
loop {
|
||||
select! {
|
||||
biased;
|
||||
_ = shutdown_rx.recv() => break,
|
||||
r = rx.recv() => match r {
|
||||
Some((url, message)) => {
|
||||
let timer = WEBHOOK_REQUEST_COUNT.start_timer();
|
||||
let _ = client.post(url).json(&message).send().await;
|
||||
timer.stop_and_record();
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self { channel: tx }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WebhookUtil {
|
||||
webhook: Option<String>,
|
||||
shared: Extension<WebhookShared>,
|
||||
}
|
||||
|
||||
impl WebhookUtil {
|
||||
pub fn send_message(&self, message: WebhookMessage) {
|
||||
let Some(webhook) = &self.webhook else {
|
||||
return;
|
||||
};
|
||||
let _ = self.shared.channel.send((webhook.clone(), message));
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for WebhookUtil
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = (StatusCode, String);
|
||||
|
||||
async fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &S,
|
||||
) -> std::result::Result<Self, Self::Rejection> {
|
||||
let original_uri = OriginalUri::from_request_parts(parts, state)
|
||||
.await
|
||||
.ok()
|
||||
.map(|x| x.0)
|
||||
.unwrap_or_default();
|
||||
let path_vec: Vec<&str> = original_uri.path().split("/").collect();
|
||||
let workspace_id = if path_vec.len() >= 4 && path_vec[0] == "" && path_vec[2] == "w" {
|
||||
Some(path_vec[3].to_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let webhook = sqlx::query_scalar!(
|
||||
"SELECT webhook FROM workspace_settings WHERE workspace_id = $1",
|
||||
workspace_id
|
||||
)
|
||||
.fetch_one(
|
||||
&Extension::<DB>::from_request_parts(parts, state)
|
||||
.await
|
||||
.map_err(|_| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"Could not aquire DB while retrieving webhook".to_owned(),
|
||||
)
|
||||
})?
|
||||
.0,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Could not execute DB query {:?}", e),
|
||||
)
|
||||
})?;
|
||||
let shared = Extension::<WebhookShared>::from_request_parts(parts, state)
|
||||
.await
|
||||
.map_err(|_| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"Could not aquire shared process while retrieving webhook".to_owned(),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Self { webhook, shared })
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/delete_invite", post(delete_invite))
|
||||
.route("/get_settings", get(get_settings))
|
||||
.route("/edit_slack_command", post(edit_slack_command))
|
||||
.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))
|
||||
@@ -90,6 +91,7 @@ pub struct WorkspaceSettings {
|
||||
pub auto_invite_operator: Option<bool>,
|
||||
pub customer_id: Option<String>,
|
||||
pub plan: Option<String>,
|
||||
pub webhook: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(FromRow, Serialize, Debug)]
|
||||
@@ -117,6 +119,11 @@ struct EditAutoInvite {
|
||||
operator: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct EditWebhook {
|
||||
webhook: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CreateWorkspace {
|
||||
id: String,
|
||||
@@ -233,38 +240,28 @@ async fn stripe_checkout(
|
||||
params.line_items = match plan.plan.as_str() {
|
||||
"team" => Some(vec![
|
||||
stripe::CreateCheckoutSessionLineItems {
|
||||
quantity: Some(1),
|
||||
price: Some("price_1MUlrWGU3NdFi9eLE9GBZhoY".to_string()),
|
||||
quantity: None,
|
||||
price: Some("price_1MSdSyGU3NdFi9eLMdV6cS6F".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
stripe::CreateCheckoutSessionLineItems {
|
||||
quantity: None,
|
||||
price: Some("price_1MUlreGU3NdFi9eLi6sOyvVa".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
stripe::CreateCheckoutSessionLineItems {
|
||||
quantity: None,
|
||||
price: Some("price_1MUlrlGU3NdFi9eLFLggSXZV".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
stripe::CreateCheckoutSessionLineItems {
|
||||
quantity: None,
|
||||
price: Some("price_1MUlr3GU3NdFi9eLbZYFjR9p".to_string()),
|
||||
price: Some("price_1MShsNGU3NdFi9eLJMEZUW8b".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
]),
|
||||
"enterprise" => Some(vec![
|
||||
stripe::CreateCheckoutSessionLineItems {
|
||||
quantity: None,
|
||||
price: Some("price_1MSdf6GU3NdFi9eLJFRkntlx".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
stripe::CreateCheckoutSessionLineItems {
|
||||
quantity: None,
|
||||
price: Some("price_1MShsNGU3NdFi9eLJMEZUW8b".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
]),
|
||||
// "enterprise" => Some(vec![
|
||||
// stripe::CreateCheckoutSessionLineItems {
|
||||
// quantity: None,
|
||||
// price: Some("price_1MSdf6GU3NdFi9eLJFRkntlx".to_string()),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// stripe::CreateCheckoutSessionLineItems {
|
||||
// quantity: None,
|
||||
// price: Some("price_1MShsNGU3NdFi9eLJMEZUW8b".to_string()),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// ]),
|
||||
_ => Err(Error::BadRequest("invalid plan".to_string()))?,
|
||||
};
|
||||
params.customer_email = Some(&authed.email);
|
||||
@@ -519,6 +516,48 @@ async fn edit_auto_invite(
|
||||
))
|
||||
}
|
||||
|
||||
async fn edit_webhook(
|
||||
authed: Authed,
|
||||
Extension(db): Extension<DB>,
|
||||
Path(w_id): Path<String>,
|
||||
Authed { is_admin, username, .. }: Authed,
|
||||
Json(ew): Json<EditWebhook>,
|
||||
) -> Result<String> {
|
||||
require_admin(is_admin, &username)?;
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
|
||||
if let Some(webhook) = &ew.webhook {
|
||||
sqlx::query!(
|
||||
"UPDATE workspace_settings SET webhook = $1 WHERE workspace_id = $2",
|
||||
webhook,
|
||||
&w_id
|
||||
)
|
||||
.execute(&mut tx)
|
||||
.await?;
|
||||
} else {
|
||||
sqlx::query!(
|
||||
"UPDATE workspace_settings SET webhook = NULL WHERE workspace_id = $1",
|
||||
&w_id,
|
||||
)
|
||||
.execute(&mut tx)
|
||||
.await?;
|
||||
}
|
||||
audit_log(
|
||||
&mut tx,
|
||||
&authed.username,
|
||||
"workspaces.edit_webhook",
|
||||
ActionKind::Update,
|
||||
&w_id,
|
||||
Some(&authed.email),
|
||||
Some([("webhook", &format!("{:?}", ew.webhook)[..])].into()),
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(format!("Edit webhook for workspace {}", &w_id))
|
||||
}
|
||||
|
||||
async fn list_workspaces_as_super_admin(
|
||||
authed: Authed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
|
||||
@@ -307,6 +307,19 @@ async fn op_get_id(args: Vec<String>) -> Result<Option<serde_json::Value>, anyho
|
||||
let node_id = &args[4];
|
||||
|
||||
let client = windmill_api_client::create_client(base_url, token.clone());
|
||||
let err = client
|
||||
.result_by_id(workspace, flow_job_id, node_id, Some(true))
|
||||
.await
|
||||
.err()
|
||||
.unwrap();
|
||||
let res = match err {
|
||||
windmill_api_client::Error::UnexpectedResponse(e) => {
|
||||
tracing::error!("{:?}", e.text().await);
|
||||
anyhow::anyhow!("bar")
|
||||
}
|
||||
_ => anyhow::anyhow!("foo"),
|
||||
};
|
||||
tracing::error!("{:?}", res);
|
||||
let result = client
|
||||
.result_by_id(workspace, flow_job_id, node_id, Some(true))
|
||||
.await
|
||||
|
||||
@@ -133,7 +133,7 @@ async fn copy_cache_to_bucket_as_tar(bucket: &str) {
|
||||
.current_dir(ROOT_CACHE_DIR)
|
||||
.arg("-c")
|
||||
.arg("-f")
|
||||
.arg(format!("{ROOT_CACHE_DIR}{TAR_CACHE_FILENAME}"))
|
||||
.arg(format!("{ROOT_CACHE_DIR}/{TAR_CACHE_FILENAME}"))
|
||||
.args(&["pip", "go", "deno"])
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
@@ -181,7 +181,7 @@ async fn copy_cache_from_bucket_as_tar(bucket: &str) -> bool {
|
||||
match Command::new("rclone")
|
||||
.arg("copyto")
|
||||
.arg(format!(":s3,env_auth=true:{bucket}/{TAR_CACHE_FILENAME}"))
|
||||
.arg(format!("{ROOT_CACHE_DIR}{TAR_CACHE_FILENAME}"))
|
||||
.arg(format!("{ROOT_CACHE_DIR}/{TAR_CACHE_FILENAME}"))
|
||||
.arg("--size-only")
|
||||
.arg("--fast-list")
|
||||
.stdin(Stdio::null())
|
||||
@@ -427,15 +427,6 @@ pub async fn run_worker(
|
||||
let deno_flags = std::env::var("DENO_FLAGS")
|
||||
.ok()
|
||||
.map(|x| x.split(' ').map(|x| x.to_string()).collect());
|
||||
let pip_local_dependencies = std::env::var("PIP_LOCAL_DEPENDENCIES")
|
||||
.ok()
|
||||
.map(|x| x.split(',').map(|x| x.to_string()).collect());
|
||||
|
||||
let pip_local_dependencies = if pip_local_dependencies == Some(vec!["".to_string()]) {
|
||||
None
|
||||
} else {
|
||||
pip_local_dependencies
|
||||
};
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
let tar_cache_rate = std::env::var("TAR_CACHE_RATE")
|
||||
@@ -443,10 +434,6 @@ pub async fn run_worker(
|
||||
.and_then(|x| x.parse::<i32>().ok())
|
||||
.unwrap_or(100);
|
||||
|
||||
let additional_python_paths = std::env::var("ADDITIONAL_PYTHON_PATHS")
|
||||
.ok()
|
||||
.map(|x| x.split(':').map(|x| x.to_string()).collect());
|
||||
|
||||
let envs = Envs {
|
||||
deno_path,
|
||||
go_path,
|
||||
@@ -460,8 +447,6 @@ pub async fn run_worker(
|
||||
max_log_size,
|
||||
deno_flags,
|
||||
deno_auth_tokens,
|
||||
pip_local_dependencies,
|
||||
additional_python_paths,
|
||||
};
|
||||
WORKER_STARTED.inc();
|
||||
|
||||
@@ -772,8 +757,6 @@ struct Envs {
|
||||
deno_auth_tokens: String,
|
||||
deno_flags: Option<Vec<String>>,
|
||||
max_log_size: i64,
|
||||
pip_local_dependencies: Option<Vec<String>>,
|
||||
additional_python_paths: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
fn extract_error_value(log_lines: &str) -> serde_json::Value {
|
||||
@@ -1623,9 +1606,7 @@ lazy_static! {
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
async fn handle_python_job(
|
||||
WorkerConfig { base_internal_url, base_url, disable_nuser, disable_nsjail, .. }: &WorkerConfig,
|
||||
envs @ Envs {
|
||||
nsjail_path, python_path, path_env, max_log_size, additional_python_paths, ..
|
||||
}: &Envs,
|
||||
envs @ Envs { nsjail_path, python_path, path_env, max_log_size, .. }: &Envs,
|
||||
requirements_o: Option<String>,
|
||||
job_dir: &str,
|
||||
worker_dir: &str,
|
||||
@@ -1641,8 +1622,7 @@ async fn handle_python_job(
|
||||
) -> error::Result<serde_json::Value> {
|
||||
create_dependencies_dir(job_dir).await;
|
||||
|
||||
let mut additional_python_paths: Vec<String> =
|
||||
additional_python_paths.to_owned().unwrap_or_else(|| vec![]);
|
||||
let mut additional_python_paths: Vec<String> = vec![];
|
||||
|
||||
let requirements = match requirements_o {
|
||||
Some(r) => r,
|
||||
@@ -1749,15 +1729,6 @@ async fn handle_python_job(
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let spread = if sig.star_kwargs {
|
||||
"args = kwargs".to_string()
|
||||
} else {
|
||||
sig.args
|
||||
.into_iter()
|
||||
.map(|x| format!("args[\"{}\"] = kwargs[\"{}\"]", x.name, x.name))
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
let wrapper_content: String = format!(
|
||||
r#"
|
||||
import json
|
||||
@@ -1774,11 +1745,9 @@ with open("args.json") as f:
|
||||
for k, v in list(kwargs.items()):
|
||||
if v == '<function call>':
|
||||
del kwargs[k]
|
||||
args = {{}}
|
||||
{spread}
|
||||
{transforms}
|
||||
try:
|
||||
res = inner_script.main(**args)
|
||||
res = inner_script.main(**kwargs)
|
||||
res_json = json.dumps(res, separators=(',', ':'), default=str).replace('\n', '')
|
||||
with open("result.json", 'w') as f:
|
||||
f.write(res_json)
|
||||
@@ -2132,14 +2101,7 @@ async fn pip_compile(
|
||||
requirements: &str,
|
||||
logs: &mut String,
|
||||
job_dir: &str,
|
||||
Envs {
|
||||
pip_extra_index_url,
|
||||
pip_index_url,
|
||||
pip_trusted_host,
|
||||
max_log_size,
|
||||
pip_local_dependencies,
|
||||
..
|
||||
}: &Envs,
|
||||
Envs { pip_extra_index_url, pip_index_url, pip_trusted_host, max_log_size, .. }: &Envs,
|
||||
db: &Pool<Postgres>,
|
||||
timeout: i32,
|
||||
) -> error::Result<String> {
|
||||
@@ -2147,15 +2109,6 @@ async fn pip_compile(
|
||||
set_logs(logs, job_id, db).await;
|
||||
logs.push_str(&format!("\ncontent of requirements:\n{}", requirements));
|
||||
let file = "requirements.in";
|
||||
let requirements = if let Some(pip_local_dependencies) = pip_local_dependencies {
|
||||
let deps = pip_local_dependencies.clone();
|
||||
requirements
|
||||
.lines()
|
||||
.filter(|s| !deps.contains(&s.to_string()))
|
||||
.join("\n")
|
||||
} else {
|
||||
requirements.to_string()
|
||||
};
|
||||
write_file(job_dir, file, &requirements).await?;
|
||||
|
||||
let mut args = vec!["-q", "--no-header", file, "--resolver=backtracking"];
|
||||
|
||||
@@ -12,7 +12,7 @@ import hub from "./hub.ts";
|
||||
import { tryResolveVersion } from "./context.ts";
|
||||
import { GlobalOptions } from "./types.ts";
|
||||
|
||||
const VERSION = "v1.61.1";
|
||||
const VERSION = "v1.60.0";
|
||||
|
||||
const command = new Command()
|
||||
.name("wmill")
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
FROM debian:buster-slim as nsjail
|
||||
|
||||
WORKDIR /nsjail
|
||||
|
||||
ARG nsjail=""
|
||||
|
||||
RUN if [ "$nsjail" = "true" ]; then apt-get -y update \
|
||||
&& apt-get install -y \
|
||||
bison=2:3.3.* \
|
||||
flex=2.6.* \
|
||||
g++=4:8.3.* \
|
||||
gcc=4:8.3.* \
|
||||
git=1:2.20.* \
|
||||
libprotobuf-dev=3.6.* \
|
||||
libnl-route-3-dev=3.4.* \
|
||||
make=4.2.* \
|
||||
pkg-config=0.29-6 \
|
||||
protobuf-compiler=3.6.*; fi
|
||||
|
||||
|
||||
RUN if [ "$nsjail" = "true" ]; then git clone -b master --single-branch https://github.com/google/nsjail.git . \
|
||||
&& git checkout dccf911fd2659e7b08ce9507c25b2b38ec2c5800; fi
|
||||
RUN if [ "$nsjail" = "true" ]; then make; else touch nsjail; fi
|
||||
|
||||
FROM rust:slim-buster AS rust_base
|
||||
|
||||
RUN apt-get update && apt-get install -y git libssl-dev pkg-config npm
|
||||
|
||||
RUN apt-get -y update \
|
||||
&& apt-get install -y \
|
||||
curl lld nodejs npm
|
||||
|
||||
RUN rustup component add rustfmt
|
||||
|
||||
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo install cargo-chef
|
||||
|
||||
WORKDIR /windmill
|
||||
|
||||
ENV SQLX_OFFLINE=true
|
||||
ENV CARGO_INCREMENTAL=1
|
||||
|
||||
FROM node:19-alpine as frontend
|
||||
|
||||
# install dependencies
|
||||
WORKDIR /frontend
|
||||
COPY ./frontend/package.json ./frontend/package-lock.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Copy all local files into the image.
|
||||
COPY frontend .
|
||||
RUN mkdir /backend
|
||||
COPY /backend/windmill-api/openapi.yaml /backend/windmill-api/openapi.yaml
|
||||
COPY /openflow.openapi.yaml /openflow.openapi.yaml
|
||||
COPY /backend/windmill-api/build_openapi.sh /backend/windmill-api/build_openapi.sh
|
||||
RUN cd /backend/windmill-api && . ./build_openapi.sh
|
||||
|
||||
RUN npm run generate-backend-client
|
||||
ENV NODE_OPTIONS "--max-old-space-size=8192"
|
||||
RUN npm run build
|
||||
RUN npm run check
|
||||
|
||||
|
||||
|
||||
FROM rust_base AS planner
|
||||
|
||||
COPY ./openflow.openapi.yaml /openflow.openapi.yaml
|
||||
COPY ./backend ./
|
||||
|
||||
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
FROM rust_base AS builder
|
||||
ARG features=""
|
||||
|
||||
COPY --from=planner /windmill/recipe.json recipe.json
|
||||
|
||||
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo chef cook --release --features "$features" --recipe-path recipe.json
|
||||
|
||||
COPY ./openflow.openapi.yaml /openflow.openapi.yaml
|
||||
COPY ./backend ./
|
||||
|
||||
COPY --from=frontend /frontend /frontend
|
||||
COPY --from=frontend /backend/windmill-api/openapi-deref.yaml ./windmill-api/openapi-deref.yaml
|
||||
COPY .git/ .git/
|
||||
|
||||
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release --features "$features"
|
||||
|
||||
|
||||
FROM python:3.10.8-slim-buster
|
||||
|
||||
ARG APP=/usr/src/app
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y ca-certificates wget curl git jq libprotobuf-dev libnl-route-3-dev unzip \
|
||||
&& apt-get install -y ca-certificates wget curl git jq libprotobuf-dev libnl-route-3-dev unzip build-essential \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \
|
||||
curl -o rclone.zip "https://downloads.rclone.org/v1.60.1/rclone-v1.60.1-linux-$arch.zip"; \
|
||||
unzip -p rclone.zip rclone-v1.60.1-linux-$arch/rclone > /usr/bin/rclone; rm rclone.zip; \
|
||||
chown root:root /usr/bin/rclone; chmod 755 /usr/bin/rclone
|
||||
|
||||
RUN set -eux; \
|
||||
arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \
|
||||
url=; \
|
||||
case "$arch" in \
|
||||
'amd64') \
|
||||
targz='go1.19.3.linux-amd64.tar.gz'; \
|
||||
;; \
|
||||
'arm64') \
|
||||
targz='go1.19.3.linux-arm64.tar.gz'; \
|
||||
;; \
|
||||
'armhf') \
|
||||
targz='go1.19.3.linux-armv6l.tar.gz'; \
|
||||
;; \
|
||||
*) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \
|
||||
esac; \
|
||||
wget "https://golang.org/dl/$targz" -nv && tar -C /usr/local -xzf "$targz" && rm "$targz";
|
||||
|
||||
ENV PATH="${PATH}:/usr/local/go/bin"
|
||||
ENV GO_PATH=/usr/local/go/bin/go
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
|
||||
RUN /usr/local/bin/python3 -m pip install pip-tools
|
||||
|
||||
COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
|
||||
|
||||
COPY --from=nsjail /nsjail/nsjail /bin/nsjail
|
||||
|
||||
COPY --from=denoland/deno:latest /usr/bin/deno /usr/bin/deno
|
||||
|
||||
RUN /usr/local/bin/python3 -m pip install openbb[all]
|
||||
|
||||
RUN mkdir -p ${APP}
|
||||
|
||||
WORKDIR ${APP}
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["./windmill"]
|
||||
62
frontend/package-lock.json
generated
62
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "windmill",
|
||||
"version": "1.61.1",
|
||||
"version": "1.60.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill",
|
||||
"version": "1.61.1",
|
||||
"version": "1.60.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
@@ -32,7 +32,7 @@
|
||||
"@playwright/test": "^1.29.2",
|
||||
"@sveltejs/adapter-static": "^1.0.0",
|
||||
"@sveltejs/kit": "^1.0.0-next.589",
|
||||
"@sveltejs/package": "^1.0.2",
|
||||
"@sveltejs/package": "^1.0.1",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.8",
|
||||
"@types/node": "^18.11.18",
|
||||
@@ -71,7 +71,7 @@
|
||||
"tailwindcss": "^3.2.2",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^4.0.4"
|
||||
"vite": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.53.1"
|
||||
@@ -828,15 +828,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/package": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-1.0.2.tgz",
|
||||
"integrity": "sha512-VY9U+05d9uNFDj7ScKRlHORYlfPSHwJewBjV+V2RsnViexpLFPUrboC9SiPYDCpLnbeqwXerxhO6twGHUBGeIA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-1.0.1.tgz",
|
||||
"integrity": "sha512-iYoDz4AEJQUfdKUfBcwtYEGYkf4NMByQL3Sl2ESnu+IXsLNsHvhH0zUDhAmUmAgcrH8fVjiR7FuJeyh+7EQtiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.3",
|
||||
"kleur": "^4.1.5",
|
||||
"sade": "^1.8.1",
|
||||
"svelte2tsx": "~0.6.0"
|
||||
"svelte2tsx": "~0.5.20"
|
||||
},
|
||||
"bin": {
|
||||
"svelte-package": "svelte-package.js"
|
||||
@@ -848,20 +848,6 @@
|
||||
"svelte": "^3.44.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/package/node_modules/svelte2tsx": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.6.0.tgz",
|
||||
"integrity": "sha512-TrxfQkO7CKi8Pu2eC/FyteDCdk3OOeQV5u6z7OjYAsOhsd0ClzAKqxJdvp6xxNQLrbFzf/XvCi9Fy8MQ1MleFA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"dedent-js": "^1.0.1",
|
||||
"pascal-case": "^3.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.55",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.0.2.tgz",
|
||||
@@ -6801,9 +6787,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz",
|
||||
"integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.0.3.tgz",
|
||||
"integrity": "sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.16.3",
|
||||
@@ -7639,27 +7625,15 @@
|
||||
}
|
||||
},
|
||||
"@sveltejs/package": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-1.0.2.tgz",
|
||||
"integrity": "sha512-VY9U+05d9uNFDj7ScKRlHORYlfPSHwJewBjV+V2RsnViexpLFPUrboC9SiPYDCpLnbeqwXerxhO6twGHUBGeIA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-1.0.1.tgz",
|
||||
"integrity": "sha512-iYoDz4AEJQUfdKUfBcwtYEGYkf4NMByQL3Sl2ESnu+IXsLNsHvhH0zUDhAmUmAgcrH8fVjiR7FuJeyh+7EQtiw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": "^3.5.3",
|
||||
"kleur": "^4.1.5",
|
||||
"sade": "^1.8.1",
|
||||
"svelte2tsx": "~0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"svelte2tsx": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.6.0.tgz",
|
||||
"integrity": "sha512-TrxfQkO7CKi8Pu2eC/FyteDCdk3OOeQV5u6z7OjYAsOhsd0ClzAKqxJdvp6xxNQLrbFzf/XvCi9Fy8MQ1MleFA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dedent-js": "^1.0.1",
|
||||
"pascal-case": "^3.1.1"
|
||||
}
|
||||
}
|
||||
"svelte2tsx": "~0.5.20"
|
||||
}
|
||||
},
|
||||
"@sveltejs/vite-plugin-svelte": {
|
||||
@@ -11937,9 +11911,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"vite": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz",
|
||||
"integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.0.3.tgz",
|
||||
"integrity": "sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esbuild": "^0.16.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "windmill",
|
||||
"version": "1.61.1",
|
||||
"version": "1.60.0",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
@@ -18,7 +18,7 @@
|
||||
"@playwright/test": "^1.29.2",
|
||||
"@sveltejs/adapter-static": "^1.0.0",
|
||||
"@sveltejs/kit": "^1.0.0-next.589",
|
||||
"@sveltejs/package": "^1.0.2",
|
||||
"@sveltejs/package": "^1.0.1",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.8",
|
||||
"@types/node": "^18.11.18",
|
||||
@@ -57,7 +57,7 @@
|
||||
"tailwindcss": "^3.2.2",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^4.0.4"
|
||||
"vite": "^4.0.3"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface SchemaProperty {
|
||||
}
|
||||
|
||||
export type Schema = {
|
||||
$schema: string | undefined
|
||||
$schema: string
|
||||
type: string
|
||||
properties: { [name: string]: SchemaProperty }
|
||||
required: string[]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import { emptySchema, emptyString } from '$lib/utils'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
|
||||
export let resource_type: string
|
||||
export let args: Record<string, any> | any = {}
|
||||
@@ -13,10 +12,7 @@
|
||||
|
||||
let schema = emptySchema()
|
||||
let notFound = false
|
||||
|
||||
async function loadSchema() {
|
||||
rawCode = '{}'
|
||||
viewJsonSchema = false
|
||||
try {
|
||||
const rt = await ResourceService.getResourceType({
|
||||
workspace: $workspaceStore!,
|
||||
@@ -25,6 +21,8 @@
|
||||
schema = rt.schema
|
||||
notFound = false
|
||||
} catch (e) {
|
||||
rawCode = '{}'
|
||||
|
||||
notFound = true
|
||||
}
|
||||
}
|
||||
@@ -45,40 +43,17 @@
|
||||
}
|
||||
let error = ''
|
||||
let rawCode = ''
|
||||
let viewJsonSchema = false
|
||||
|
||||
$: rawCode && parseJson()
|
||||
|
||||
function switchTab(asJson: boolean) {
|
||||
viewJsonSchema = asJson
|
||||
if (asJson) {
|
||||
rawCode = JSON.stringify(args, null, 2)
|
||||
} else {
|
||||
parseJson()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if !notFound}
|
||||
<div class="w-full flex flex-row-reverse">
|
||||
<Toggle
|
||||
on:change={(e) => switchTab(e.detail)}
|
||||
options={{
|
||||
right: 'As JSON'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
{#if notFound}
|
||||
<p class="italic text-gray-500 text-xs mb-4"
|
||||
>No corresponding resource type found in your workspace for {resource_type}. Define the value in
|
||||
JSON directly</p
|
||||
>
|
||||
{/if}
|
||||
{#if notFound || viewJsonSchema}
|
||||
{#if !emptyString(error)}<span class="text-red-400 text-xs mb-1 flex flex-row-reverse"
|
||||
>{error}</span
|
||||
>{:else}<div class="py-2" />{/if}
|
||||
<SimpleEditor autoHeight lang="json" bind:code={rawCode} fixedOverflowWidgets={false} />
|
||||
{:else}
|
||||
<SchemaForm noDelete {password} isValid {schema} bind:args />
|
||||
<SchemaForm {password} isValid {schema} bind:args />
|
||||
{/if}
|
||||
|
||||
@@ -155,7 +155,6 @@
|
||||
async function next() {
|
||||
if (step == 1 && manual) {
|
||||
step += 1
|
||||
args = {}
|
||||
} else if (step == 1 && !manual) {
|
||||
const url = new URL(`/api/oauth/connect/${resource_type}`, $page.url.origin)
|
||||
url.searchParams.append('scopes', scopes.join('+'))
|
||||
@@ -411,17 +410,15 @@
|
||||
</ol>
|
||||
</div>
|
||||
{#if apiTokenApps[resource_type].img}
|
||||
<div class="mt-4 w-full overflow-hidden">
|
||||
<img class="m-auto max-h-60" alt="connect" src={apiTokenApps[resource_type].img} />
|
||||
<div class="mt-4 w-full">
|
||||
<img class="max-h-96 m-auto" alt="connect" src={apiTokenApps[resource_type].img} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<h2 class="mt-4">Value</h2>
|
||||
<div class="mt-4">
|
||||
{#key resource_type}
|
||||
<ApiConnectForm password={key ?? ''} {resource_type} bind:args bind:isValid />
|
||||
{/key}
|
||||
<ApiConnectForm password={key ?? ''} {resource_type} bind:args bind:isValid />
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4 mb-2">Description</h2>
|
||||
|
||||
@@ -7,13 +7,11 @@
|
||||
import autosize from 'svelte-autosize'
|
||||
|
||||
export let result: any
|
||||
export let requireHtmlApproval = false
|
||||
|
||||
let resultKind:
|
||||
| 'json'
|
||||
| 'table-col'
|
||||
| 'table-row'
|
||||
| 'html'
|
||||
| 'png'
|
||||
| 'file'
|
||||
| 'jpeg'
|
||||
@@ -21,11 +19,9 @@
|
||||
| 'error'
|
||||
| 'approval'
|
||||
| undefined
|
||||
|
||||
$: resultKind = inferResultKind(result)
|
||||
|
||||
let forceJson = false
|
||||
let enableHtml = false
|
||||
|
||||
function isRectangularArray(obj: any) {
|
||||
if (!Array.isArray(obj) || obj.length == 0) {
|
||||
@@ -57,8 +53,6 @@
|
||||
return 'table-row'
|
||||
} else if (keys.map((k) => Array.isArray(result[k])).reduce((a, b) => a && b)) {
|
||||
return 'table-col'
|
||||
} else if (keys.length == 1 && keys[0] == 'html') {
|
||||
return 'html'
|
||||
} else if (keys.length == 1 && keys[0] == 'png') {
|
||||
return 'png'
|
||||
} else if (keys.length == 1 && keys[0] == 'jpeg') {
|
||||
@@ -125,34 +119,6 @@
|
||||
</tbody>
|
||||
</TableCustom>
|
||||
</div>
|
||||
{:else if !forceJson && resultKind == 'html'}
|
||||
<div class="h-full">
|
||||
{#if !requireHtmlApproval || enableHtml}
|
||||
{@html result.html}
|
||||
{:else}
|
||||
<div class="font-main text-sm">
|
||||
<div class="flex flex-col">
|
||||
<div class="bg-red-400 py-1 rounded-t text-white font-bold text-center">
|
||||
Warning
|
||||
</div>
|
||||
<p
|
||||
class="text-gray-600 mb-2 text-left border-2 !border-t-0 rounded-b border-red-400 overflow-auto p-1"
|
||||
>Rendering HTML can expose you to <a href="https://owasp.org/www-community/attacks/xss/" target="_blank" rel="noreferrer" class="hover:underline">XSS attacks</a>.
|
||||
Only enable it if you trust the author of the script.
|
||||
</p>
|
||||
</div>
|
||||
<div class="center-center">
|
||||
<Button
|
||||
size="sm"
|
||||
color="dark"
|
||||
on:click={() => enableHtml = true}
|
||||
>
|
||||
Enable HTML rendering
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if !forceJson && resultKind == 'png'}
|
||||
<div class="h-full"
|
||||
><img alt="png rendered" class="w-auto h-full" src="data:image/png;base64,{result.png}" />
|
||||
|
||||
@@ -60,11 +60,7 @@
|
||||
}
|
||||
|
||||
if (isCodeInjection(rawValue)) {
|
||||
arg.expr = getDefaultExpr(
|
||||
argName,
|
||||
previousModuleId,
|
||||
`\`${rawValue.toString().replaceAll('`', '\\`')}\``
|
||||
)
|
||||
arg.expr = getDefaultExpr(argName, previousModuleId, `\`${rawValue}\``)
|
||||
arg.type = 'javascript'
|
||||
propertyType = 'static'
|
||||
} else {
|
||||
@@ -121,13 +117,9 @@
|
||||
const openBracket = '${'
|
||||
const closeBracket = '}'
|
||||
|
||||
function setDefaultCode() {
|
||||
if (!arg?.value) {
|
||||
monacoTemplate?.setCode(schema.properties[argName].default)
|
||||
}
|
||||
}
|
||||
|
||||
$: schema.properties[argName].default && setDefaultCode()
|
||||
$: schema.properties[argName].default &&
|
||||
!arg?.value &&
|
||||
monacoTemplate?.setCode(schema.properties[argName].default)
|
||||
</script>
|
||||
|
||||
{#if arg != undefined}
|
||||
@@ -165,7 +157,7 @@
|
||||
argName,
|
||||
previousModuleId,
|
||||
staticTemplate
|
||||
? `\`${arg?.value.toString().replaceAll('`', '\\`') ?? ''}\``
|
||||
? `\`${arg?.value ?? ''}\``
|
||||
: arg.value
|
||||
? JSON.stringify(arg?.value, null, 4)
|
||||
: ''
|
||||
@@ -180,7 +172,6 @@
|
||||
if (staticTemplate) {
|
||||
if (arg) {
|
||||
arg.value = codeToStaticTemplate(arg.expr)
|
||||
arg.expr = undefined
|
||||
}
|
||||
setPropertyType(arg?.value)
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
import { faSave } from '@fortawesome/free-solid-svg-icons'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
|
||||
let path = ''
|
||||
let initialPath = ''
|
||||
@@ -39,7 +38,6 @@
|
||||
path = p
|
||||
resourceToEdit = undefined
|
||||
resourceSchema = undefined
|
||||
viewJsonSchema = false
|
||||
loadingSchema = true
|
||||
drawer.openDrawer?.()
|
||||
resourceToEdit = await ResourceService.getResource({ workspace: $workspaceStore!, path: p })
|
||||
@@ -113,16 +111,6 @@
|
||||
args[k] = `$var:${path}`
|
||||
})
|
||||
}
|
||||
let viewJsonSchema = false
|
||||
|
||||
function switchTab(asJson: boolean) {
|
||||
viewJsonSchema = asJson
|
||||
if (asJson) {
|
||||
rawCode = JSON.stringify(args, null, 2)
|
||||
} else {
|
||||
parseJson()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawer} size="800px">
|
||||
@@ -148,21 +136,12 @@
|
||||
kind="resource"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex w-full justify-between max-w-lg items-center mt-4">
|
||||
<h3>Value</h3>
|
||||
<Toggle
|
||||
on:change={(e) => switchTab(e.detail)}
|
||||
options={{
|
||||
right: 'As JSON'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<h3 class="mt-4">Value</h3>
|
||||
<div class="text-sm">
|
||||
{#if loadingSchema}
|
||||
<Skeleton layout={[[4]]} />
|
||||
{:else if !viewJsonSchema && resourceSchema && resourceSchema?.properties}
|
||||
{:else if resourceSchema && resourceSchema?.properties}
|
||||
<SchemaForm
|
||||
noDelete
|
||||
disabled={!can_write}
|
||||
compact
|
||||
schema={resourceSchema}
|
||||
@@ -172,13 +151,10 @@
|
||||
{:else if !can_write}
|
||||
<input type="text" disabled value={rawCode} />
|
||||
{:else}
|
||||
{#if !viewJsonSchema}
|
||||
<p class="italic text-gray-500 text-xs mb-4"
|
||||
>No corresponding resource type found in your workspace for {selectedResourceType}.
|
||||
Define the value in JSON directly</p
|
||||
>
|
||||
{/if}
|
||||
|
||||
<p class="italic text-gray-500 text-xs mb-4"
|
||||
>No corresponding resource type found in your workspace for {selectedResourceType}.
|
||||
Define the value in JSON directly</p
|
||||
>
|
||||
{#if !emptyString(jsonError)}<span
|
||||
class="text-red-400 text-xs mb-1 flex flex-row-reverse">{jsonError}</span
|
||||
>{:else}<div class="py-2" />{/if}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
export let filter: string[] | undefined = undefined
|
||||
export let noDynamicToggle = false
|
||||
export let flexWrap = false
|
||||
export let noDelete = false
|
||||
|
||||
let clazz: string = ''
|
||||
export { clazz as class }
|
||||
@@ -60,9 +59,7 @@
|
||||
let lkeys = Object.keys(schema?.properties ?? {})
|
||||
if (schema?.properties && JSON.stringify(lkeys) != JSON.stringify(keys)) {
|
||||
keys = lkeys
|
||||
if (!noDelete) {
|
||||
removeExtraKey()
|
||||
}
|
||||
removeExtraKey()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<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
|
||||
|
||||
const requireHtmlApproval = getContext<boolean | undefined>(IS_APP_PUBLIC_CONTEXT_KEY)
|
||||
let result: any = undefined
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
@@ -19,6 +16,6 @@
|
||||
Results
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<DisplayResult {result} {requireHtmlApproval} />
|
||||
<DisplayResult {result} />
|
||||
</div>
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import type { AppInput } from '../../inputType'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
|
||||
export const staticOutputs: string[] = ['result', 'loading']
|
||||
|
||||
let result: object | undefined = undefined
|
||||
let divEl: HTMLDivElement | null = null
|
||||
|
||||
let Plotly
|
||||
onMount(async () => {
|
||||
if (divEl) {
|
||||
//@ts-ignore
|
||||
await import('https://cdn.plot.ly/plotly-2.18.0.min.js')
|
||||
|
||||
Plotly = window['Plotly']
|
||||
}
|
||||
})
|
||||
|
||||
let h: number | undefined = undefined
|
||||
let w: number | undefined = undefined
|
||||
|
||||
$: Plotly &&
|
||||
result &&
|
||||
divEl &&
|
||||
h &&
|
||||
w &&
|
||||
Plotly.newPlot(
|
||||
divEl,
|
||||
[result],
|
||||
{ width: w, height: h, margin: { l: 40, r: 40, b: 40, t: 40, pad: 4 } },
|
||||
{ responsive: true, displayModeBar: false }
|
||||
)
|
||||
</script>
|
||||
|
||||
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
|
||||
<RunnableWrapper flexWrap bind:componentInput {id} bind:result>
|
||||
{#if !Plotly}
|
||||
<div class="p-2">
|
||||
<Loader2 class="animate-spin" />
|
||||
</div>
|
||||
{/if}
|
||||
<div on:pointerdown bind:this={divEl} />
|
||||
</RunnableWrapper>
|
||||
</div>
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { parse } from 'path'
|
||||
import { onMount } from 'svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { AppComponent } from '../types'
|
||||
import { displayData } from '../utils'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let resourceOnly = false
|
||||
</script>
|
||||
|
||||
{#if component?.componentInput?.type === 'runnable' && Object.keys(component?.componentInput?.fields ?? {}).length > 0}
|
||||
<div class="mb-8">
|
||||
<div class="flex justify-between mb-4">
|
||||
<span class="text-sm font-bold">{component.id}</span>
|
||||
<span class="text-sm font-bold">{displayData[component.type].name}</span>
|
||||
</div>
|
||||
|
||||
{#if resourceOnly && Object.keys(component.componentInput.fields).filter((fieldKey) => {
|
||||
if (component?.componentInput?.type === 'runnable') {
|
||||
const fields = component.componentInput?.fields
|
||||
const field = fields[fieldKey]
|
||||
return field.fieldType === 'object' && field.format?.startsWith('resource-')
|
||||
}
|
||||
return false
|
||||
}).length === 0}
|
||||
<span class="text-sm">No resource input</span>
|
||||
{:else}
|
||||
<InputsSpecsEditor
|
||||
id={component.id}
|
||||
shouldCapitalize={false}
|
||||
bind:inputSpecs={component.componentInput.fields}
|
||||
userInputEnabled={component.type !== 'buttoncomponent'}
|
||||
{resourceOnly}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,18 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { ConnectedAppInput, RowAppInput, StaticAppInput, UserAppInput } from '../inputType'
|
||||
import type { AppComponent } from '../types'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
|
||||
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
export let component: AppComponent
|
||||
export let resourceOnly: boolean = false
|
||||
|
||||
$: fields = resourceOnly ? fields : fields
|
||||
</script>
|
||||
|
||||
<InputsSpecsEditor
|
||||
id={component.id}
|
||||
shouldCapitalize={false}
|
||||
bind:inputSpecs={fields}
|
||||
userInputEnabled={component.type !== 'buttoncomponent'}
|
||||
/>
|
||||
@@ -39,7 +39,6 @@
|
||||
export let initialMode: EditorMode = 'dnd'
|
||||
export let policy: Policy
|
||||
export let summary: string
|
||||
export let fromHub: boolean = false
|
||||
|
||||
const appStore = writable<App>(app)
|
||||
const worldStore = writable<World | undefined>(undefined)
|
||||
@@ -126,7 +125,7 @@
|
||||
{#if !$userStore?.operator}
|
||||
<UnsavedConfirmationModal />
|
||||
{#if initialMode !== 'preview'}
|
||||
<AppEditorHeader {policy} {fromHub} />
|
||||
<AppEditorHeader {policy} />
|
||||
{/if}
|
||||
|
||||
{#if previewing}
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
Loader2,
|
||||
MoreVertical,
|
||||
Pencil,
|
||||
SlidersHorizontal,
|
||||
Smartphone
|
||||
} from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
@@ -52,7 +51,6 @@
|
||||
import type { AppComponent, AppEditorContext } from '../types'
|
||||
import { toStatic } from '../utils'
|
||||
import AppExportButton from './AppExportButton.svelte'
|
||||
import AppInputs from './AppInputs.svelte'
|
||||
import PanelSection from './settingsPanel/common/PanelSection.svelte'
|
||||
|
||||
async function hash(message) {
|
||||
@@ -64,7 +62,6 @@
|
||||
}
|
||||
|
||||
export let policy: Policy
|
||||
export let fromHub: boolean = false
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -96,12 +93,12 @@
|
||||
|
||||
let newPath: string = ''
|
||||
let pathError: string | undefined = undefined
|
||||
|
||||
let appExport: AppExportButton
|
||||
|
||||
let saveDrawerOpen = false
|
||||
let jobsDrawerOpen = false
|
||||
let publishDrawerOpen = false
|
||||
let inputsDrawerOpen = fromHub
|
||||
|
||||
function closeSaveDrawer() {
|
||||
saveDrawerOpen = false
|
||||
@@ -251,12 +248,6 @@
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<Drawer bind:open={inputsDrawerOpen} size="600px">
|
||||
<DrawerContent title="App inputs configuration" on:close={() => (inputsDrawerOpen = false)}>
|
||||
<AppInputs />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<Drawer bind:open={jobsDrawerOpen} size="900px">
|
||||
<DrawerContent noPadding title="Debug Runs" on:close={() => (jobsDrawerOpen = false)}>
|
||||
<Splitpanes class="!overflow-visible">
|
||||
@@ -488,14 +479,6 @@
|
||||
>
|
||||
<MoreVertical size={20} />
|
||||
</Dropdown>
|
||||
<span class="hidden md:inline">
|
||||
<Button on:click={() => (inputsDrawerOpen = true)} color="light" size="xs" variant="border">
|
||||
<span class="flex gap-2">
|
||||
<SlidersHorizontal size={14} />
|
||||
App inputs
|
||||
</span>
|
||||
</Button>
|
||||
</span>
|
||||
<span class="hidden md:inline">
|
||||
<Button
|
||||
on:click={() => (jobsDrawerOpen = true)}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Alert } from '$lib/components/common'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import AppComponentInput from './AppComponentInput.svelte'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
|
||||
const { app, lazyGrid } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let resourceOnly: boolean = true
|
||||
</script>
|
||||
|
||||
<Alert type="info" title="Configurations">
|
||||
In order to properly configure the app, you need to fill in the inputs below.
|
||||
</Alert>
|
||||
<Toggle bind:checked={resourceOnly} options={{ right: 'Resource only' }} />
|
||||
{#each $lazyGrid as gridItem (gridItem.data.id)}
|
||||
{#if gridItem.data.type === 'tablecomponent'}
|
||||
<div>
|
||||
<AppComponentInput bind:component={gridItem.data} {resourceOnly} />
|
||||
<div class="ml-4 mt-4">
|
||||
{#each gridItem.data.actionButtons as actionButton (actionButton.id)}
|
||||
<AppComponentInput bind:component={actionButton.data} {resourceOnly} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<AppComponentInput bind:component={gridItem.data} {resourceOnly} />
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#if $app?.hiddenInlineScripts?.length > 0}
|
||||
<span class="font-bold text-sm">Background script inputs</span>
|
||||
<div class="gap-4 flex flex-col">
|
||||
{#each $app?.hiddenInlineScripts ?? [] as script, index (script.name)}
|
||||
<span class="text-sm">{script.name}</span>
|
||||
|
||||
{#if resourceOnly && Object.keys(script.fields).filter((fieldKey) => {
|
||||
const fields = script.fields
|
||||
const field = fields[fieldKey]
|
||||
return field.fieldType === 'object' && field.format?.startsWith('resource-')
|
||||
}).length === 0}
|
||||
<span class="text-sm">No resource input</span>
|
||||
{:else}
|
||||
<InputsSpecsEditor
|
||||
id={`bg_${index}`}
|
||||
shouldCapitalize={false}
|
||||
bind:inputSpecs={script.fields}
|
||||
userInputEnabled={false}
|
||||
{resourceOnly}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -21,7 +21,6 @@
|
||||
import AppSliderInputs from '../components/numberInputs/AppSliderInputs.svelte'
|
||||
import AppFormButton from '../components/form/AppFormButton.svelte'
|
||||
import VegaLiteHtml from '../components/dataDisplay/VegaLiteHtml.svelte'
|
||||
import PlotlyHtml from '../components/dataDisplay/PlotlyHtml.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
@@ -87,12 +86,6 @@
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'plotlycomponent'}
|
||||
<PlotlyHtml
|
||||
{...component}
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'scatterchartcomponent'}
|
||||
<AppScatterChart
|
||||
{...component}
|
||||
|
||||
@@ -39,8 +39,7 @@
|
||||
'piechartcomponent',
|
||||
'displaycomponent',
|
||||
'scatterchartcomponent',
|
||||
'vegalitecomponent',
|
||||
'plotlycomponent'
|
||||
'vegalitecomponent'
|
||||
],
|
||||
'3:10-6:10': ['tablecomponent']
|
||||
}
|
||||
@@ -56,10 +55,7 @@
|
||||
function addComponent(appComponent: AppComponent) {
|
||||
$dirtyStore = true
|
||||
const grid = $app.grid ?? []
|
||||
const id = getNextId(
|
||||
grid.map((gridItem) => gridItem.data.id),
|
||||
true
|
||||
)
|
||||
const id = getNextId(grid.map((gridItem) => gridItem.data.id))
|
||||
|
||||
appComponent.id = id
|
||||
|
||||
|
||||
@@ -328,28 +328,6 @@ const display: ComponentSet = {
|
||||
},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: false,
|
||||
id: 'plotlycomponent',
|
||||
type: 'plotlycomponent',
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: {
|
||||
type: 'bar',
|
||||
x: [1, 2, 3, 4],
|
||||
y: [5, 10, 2, 8],
|
||||
marker: {
|
||||
color: '#C8A2C8',
|
||||
line: {
|
||||
width: 2.5
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
configuration: {},
|
||||
card: false
|
||||
},
|
||||
{
|
||||
softWrap: true,
|
||||
horizontalAlignment: 'left',
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { Script, type Preview } from '$lib/gen'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { initialCode } from '$lib/script_helpers'
|
||||
import { capitalize, emptySchema } from '$lib/utils'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import { fly } from 'svelte/transition'
|
||||
import { defaultCode } from '../../editorUtils'
|
||||
@@ -61,7 +61,7 @@
|
||||
<div class="flex gap-2 flex-row flex-wrap">
|
||||
{#each langs as lang}
|
||||
<FlowScriptPicker
|
||||
label={capitalize(lang)}
|
||||
label={lang}
|
||||
{lang}
|
||||
on:click={() => {
|
||||
createInlineScriptByLanguage(lang, name)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { faTrash } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher, getContext, onMount } from 'svelte'
|
||||
import type { AppEditorContext, InlineScript } from '../../types'
|
||||
import { CheckCircle, Code2, Maximize2, Trash2, X } from 'lucide-svelte'
|
||||
import { CheckCircle, Code2, X } from 'lucide-svelte'
|
||||
import InlineScriptEditorDrawer from './InlineScriptEditorDrawer.svelte'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import type { Schema } from '$lib/common'
|
||||
@@ -13,7 +13,6 @@
|
||||
import Editor from '$lib/components/Editor.svelte'
|
||||
import { emptySchema, scriptLangToEditorLang } from '$lib/utils'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import Popover from '../../../Popover.svelte'
|
||||
|
||||
let inlineScriptEditorDrawer: InlineScriptEditorDrawer
|
||||
|
||||
@@ -58,51 +57,21 @@
|
||||
<InlineScriptEditorDrawer {editor} bind:this={inlineScriptEditorDrawer} bind:inlineScript />
|
||||
|
||||
<div class="h-full flex flex-col gap-1" transition:fly|local={{ duration: 50 }}>
|
||||
<div class="flex justify-between w-full gap-2 px-2 pt-1 flex-row items-center">
|
||||
<div class="flex justify-between w-full gap-1 px-2 pt-1 flex-row items-center">
|
||||
{#if name !== undefined}
|
||||
<input bind:value={name} placeholder="Inline script name" />
|
||||
{/if}
|
||||
<div class="flex w-full flex-row gap-2 items-center justify-end">
|
||||
{#if validCode}
|
||||
<Badge color="green" baseClass="!p-0 !h-[30px] aspect-square center-center">
|
||||
<Badge color="green">
|
||||
<CheckCircle size={16} />
|
||||
</Badge>
|
||||
{:else}
|
||||
<Badge color="red" baseClass="!p-0 !h-[30px] aspect-square center-center">
|
||||
<Badge color="red">
|
||||
<X size={16} />
|
||||
</Badge>
|
||||
{/if}
|
||||
|
||||
{#if id.startsWith('unused-') || id.startsWith('bg_')}
|
||||
<Popover notClickable placement="bottom">
|
||||
<Button
|
||||
size="xs"
|
||||
color="red"
|
||||
variant="border"
|
||||
btnClasses="!px-1.5"
|
||||
aria-label="Delete"
|
||||
on:click={() => dispatch('delete')}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</Button>
|
||||
<svelte:fragment slot="text">Delete</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
<Popover notClickable placement="bottom">
|
||||
<Button
|
||||
size="xs"
|
||||
color="blue"
|
||||
variant="border"
|
||||
btnClasses="!px-1.5"
|
||||
aria-label="Open full editor"
|
||||
on:click={() => {
|
||||
inlineScriptEditorDrawer?.openDrawer()
|
||||
}}
|
||||
>
|
||||
<Maximize2 size={16} />
|
||||
</Button>
|
||||
<svelte:fragment slot="text">Open full editor</svelte:fragment>
|
||||
</Popover>
|
||||
<Button
|
||||
variant="border"
|
||||
size="xs"
|
||||
@@ -111,8 +80,18 @@
|
||||
editor.format()
|
||||
}}
|
||||
>
|
||||
Format <Tooltip placement="bottom">Ctrl+S</Tooltip>
|
||||
Format <Tooltip>Ctrl+S</Tooltip>
|
||||
</Button>
|
||||
{#if id.startsWith('unused-') || id.startsWith('bg_')}
|
||||
<Button
|
||||
size="xs"
|
||||
color="light"
|
||||
variant="border"
|
||||
iconOnly
|
||||
startIcon={{ icon: faTrash }}
|
||||
on:click={() => dispatch('delete')}
|
||||
/>
|
||||
{/if}
|
||||
{#if $runnableComponents[id] != undefined}
|
||||
<Button
|
||||
loading={runLoading}
|
||||
@@ -125,9 +104,22 @@
|
||||
}}
|
||||
>
|
||||
Run
|
||||
<Tooltip light placement="bottom">Ctrl+Enter</Tooltip>
|
||||
<Tooltip light>Ctrl+Enter</Tooltip>
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
<Button
|
||||
size="xs"
|
||||
color="blue"
|
||||
on:click={() => {
|
||||
inlineScriptEditorDrawer?.openDrawer()
|
||||
}}
|
||||
>
|
||||
<div class="flex gap-1 items-center">
|
||||
<Code2 size={16} />
|
||||
Open full editor
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Badge, Button } from '$lib/components/common'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { classNames } from '$lib/utils'
|
||||
import { faPlus } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
@@ -7,11 +9,8 @@
|
||||
import PanelSection from '../settingsPanel/common/PanelSection.svelte'
|
||||
import { getAppScripts } from './utils'
|
||||
|
||||
const PREFIX = 'script-selector-' as const
|
||||
|
||||
export let selectedScriptComponentId: string | undefined = undefined
|
||||
const { app, selectedComponent, lazyGrid } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let list: HTMLElement
|
||||
|
||||
function selectInlineScript(id: string) {
|
||||
selectedScriptComponentId = id
|
||||
@@ -22,20 +21,13 @@
|
||||
|
||||
$: runnables = getAppScripts($lazyGrid)
|
||||
|
||||
// When selected component changes, update selectedScriptComponentId
|
||||
$: if (selectedComponent) {
|
||||
selectedScriptComponentId = $selectedComponent
|
||||
// When seleced component changes, update selectedScriptComponentId
|
||||
$: {
|
||||
if (selectedComponent) {
|
||||
selectedScriptComponentId = $selectedComponent
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't work for some reason
|
||||
// $: if (selectedScriptComponentId) {
|
||||
// const selected = document.getElementById(PREFIX + selectedScriptComponentId)
|
||||
// if(selected) {
|
||||
// const top = selected.getBoundingClientRect().top - list.getBoundingClientRect().top + list.scrollTop
|
||||
// list.scrollTo({ top, behavior: 'smooth' })
|
||||
// }
|
||||
// }
|
||||
|
||||
function createBackgroundScript() {
|
||||
let index = 0
|
||||
let newScriptPath = `Background Script ${index}`
|
||||
@@ -57,27 +49,28 @@
|
||||
fields: {}
|
||||
})
|
||||
$app.hiddenInlineScripts = $app.hiddenInlineScripts
|
||||
selectInlineScript(`bg_${$app.hiddenInlineScripts.length - 1}`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={list} class="min-h-full flex flex-col gap-4">
|
||||
<div class="min-h-full flex flex-col gap-4">
|
||||
<PanelSection title="Inline scripts" smallPadding>
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
{#if runnables.inline.length > 0}
|
||||
<div class="flex gap-2 flex-col ">
|
||||
{#each runnables.inline as { name, id }, index (index)}
|
||||
<button
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center p-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="{classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-sm cursor-pointer hover:bg-blue-50 hover:text-blue-400',
|
||||
selectedScriptComponentId === id ? 'border-blue-500 border' : ''
|
||||
)},"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
>
|
||||
<span class="text-xs truncate">{name}</span>
|
||||
<div>
|
||||
<Badge color="dark-indigo">{id}</Badge>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -85,16 +78,17 @@
|
||||
{#if $app.unusedInlineScripts?.length > 0}
|
||||
<div class="flex gap-2 flex-col ">
|
||||
{#each $app.unusedInlineScripts as unusedInlineScript, index (index)}
|
||||
{@const id = `unused-${index}`}
|
||||
<button
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center p-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="{classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-blue-50 hover:text-blue-400',
|
||||
selectedScriptComponentId === `unused-${index}` ? 'bg-blue-100 text-blue-600' : ''
|
||||
)},"
|
||||
on:click={() => selectInlineScript(`unused-${index}`)}
|
||||
>
|
||||
<span class="text-xs truncate">{unusedInlineScript.name}</span>
|
||||
<Badge color="red">Detached</Badge>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -110,15 +104,17 @@
|
||||
{#if runnables.imported.length > 0}
|
||||
<div class="flex gap-2 flex-col ">
|
||||
{#each runnables.imported as { name, id }, index (index)}
|
||||
<button
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center p-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="{classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-blue-50 hover:text-blue-400',
|
||||
selectedScriptComponentId === id ? 'bg-blue-100 text-blue-600' : ''
|
||||
)},"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
>
|
||||
<span class="text-xs truncate">{name}</span>
|
||||
<Badge color="dark-indigo">{id}</Badge>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
@@ -127,31 +123,31 @@
|
||||
</div>
|
||||
</PanelSection>
|
||||
|
||||
<PanelSection
|
||||
title="Background scripts"
|
||||
tooltip="Background scripts are triggered upon global refresh or when their input changes. The result
|
||||
of a background script can be shared among many components."
|
||||
smallPadding
|
||||
>
|
||||
<PanelSection title="Background scripts" smallPadding>
|
||||
<svelte:fragment slot="action">
|
||||
<Button size="xs" color="dark" startIcon={{ icon: faPlus }} on:click={createBackgroundScript}>
|
||||
Add
|
||||
</Button>
|
||||
<Tooltip>
|
||||
Background scripts are triggered upon global refresh or when their input changes. The result
|
||||
of a background script can be shared among many components.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
{#if $app.hiddenInlineScripts?.length > 0}
|
||||
<div class="flex gap-2 flex-col ">
|
||||
{#each $app.hiddenInlineScripts as { name }, index (index)}
|
||||
{@const id = `bg_${index}`}
|
||||
<button
|
||||
id={PREFIX + id}
|
||||
class="border flex gap-1 truncate font-normal justify-between w-full items-center p-2 rounded-sm duration-200
|
||||
{selectedScriptComponentId === id ? 'border-blue-500 bg-blue-100' : 'hover:bg-blue-50'}"
|
||||
on:click={() => selectInlineScript(id)}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="{classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-blue-50 hover:text-blue-400',
|
||||
selectedScriptComponentId === `bg_${index}` ? 'bg-blue-100 text-blue-600' : ''
|
||||
)},"
|
||||
on:click={() => selectInlineScript(`bg_${index}`)}
|
||||
>
|
||||
<span class="text-xs truncate">{name}</span>
|
||||
<Badge color="yellow">Background</Badge>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
export let userInputEnabled: boolean = true
|
||||
export let shouldCapitalize: boolean = true
|
||||
export let rowColumns = false
|
||||
export let resourceOnly = false
|
||||
|
||||
const { connectingInput } = getContext<AppEditorContext>('AppEditorContext')
|
||||
</script>
|
||||
@@ -23,99 +22,97 @@
|
||||
<div class="w-full flex flex-col gap-4">
|
||||
{#each Object.keys(inputSpecs) as inputSpecKey (inputSpecKey)}
|
||||
{@const input = inputSpecs[inputSpecKey]}
|
||||
{#if !(resourceOnly && (input.fieldType !== 'object' || !input.format?.startsWith('resource-')))}
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-end gap-1">
|
||||
<span class="text-sm font-semibold truncate">
|
||||
{shouldCapitalize
|
||||
? capitalize(addWhitespaceBeforeCapitals(inputSpecKey))
|
||||
: inputSpecKey}
|
||||
{#if input.tooltip}
|
||||
<Tooltip>
|
||||
{input.tooltip}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</span>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-end gap-1">
|
||||
<span class="text-sm font-semibold truncate">
|
||||
{shouldCapitalize
|
||||
? capitalize(addWhitespaceBeforeCapitals(inputSpecKey))
|
||||
: inputSpecKey}
|
||||
{#if input.tooltip}
|
||||
<Tooltip>
|
||||
{input.tooltip}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<div class="flex gap-x-2 gap-y-1 flex-wrap justify-end items-center">
|
||||
<Badge color="blue">
|
||||
{input.fieldType === 'array' && input.subFieldType
|
||||
? `${capitalize(fieldTypeToTsType(input.subFieldType))}[]`
|
||||
: capitalize(fieldTypeToTsType(input.fieldType))}
|
||||
</Badge>
|
||||
<div class="flex gap-x-2 gap-y-1 flex-wrap justify-end items-center">
|
||||
<Badge color="blue">
|
||||
{input.fieldType === 'array' && input.subFieldType
|
||||
? `${capitalize(fieldTypeToTsType(input.subFieldType))}[]`
|
||||
: capitalize(fieldTypeToTsType(input.fieldType))}
|
||||
</Badge>
|
||||
|
||||
{#if !inputSpecs[inputSpecKey].onlyStatic && inputSpecs[inputSpecKey].type != 'eval'}
|
||||
<ToggleButtonGroup
|
||||
bind:selected={inputSpecs[inputSpecKey].type}
|
||||
on:selected={(e) => {
|
||||
if (e.detail == 'connected' && !inputSpecs[inputSpecKey]['connection']) {
|
||||
$connectingInput = {
|
||||
opened: true,
|
||||
input: undefined,
|
||||
hoveredComponent: undefined
|
||||
}
|
||||
{#if !inputSpecs[inputSpecKey].onlyStatic && inputSpecs[inputSpecKey].type != 'eval'}
|
||||
<ToggleButtonGroup
|
||||
bind:selected={inputSpecs[inputSpecKey].type}
|
||||
on:selected={(e) => {
|
||||
if (e.detail == 'connected' && !inputSpecs[inputSpecKey]['connection']) {
|
||||
$connectingInput = {
|
||||
opened: true,
|
||||
input: undefined,
|
||||
hoveredComponent: undefined
|
||||
}
|
||||
}}
|
||||
>
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="left"
|
||||
value="static"
|
||||
startIcon={{ icon: faPen }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">Static</svelte:fragment>
|
||||
</Popover>
|
||||
{#if rowColumns}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="left"
|
||||
value="static"
|
||||
startIcon={{ icon: faPen }}
|
||||
position="center"
|
||||
value="row"
|
||||
startIcon={{ icon: faTableCells }}
|
||||
size="xs"
|
||||
>
|
||||
<Tooltip scale={0.6} placement="top-end" wrapperClass="center-center">
|
||||
Use the column name to have the value of the cell be passed to the action
|
||||
</Tooltip>
|
||||
</ToggleButton>
|
||||
<svelte:fragment slot="text">Column</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
{#if userInputEnabled && !input.format?.startsWith('resource-')}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="center"
|
||||
value="user"
|
||||
startIcon={{ icon: faUser }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">Static</svelte:fragment>
|
||||
<svelte:fragment slot="text">User Input</svelte:fragment>
|
||||
</Popover>
|
||||
{#if rowColumns}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="center"
|
||||
value="row"
|
||||
startIcon={{ icon: faTableCells }}
|
||||
size="xs"
|
||||
>
|
||||
<Tooltip scale={0.6} placement="top-end" wrapperClass="center-center">
|
||||
Use the column name to have the value of the cell be passed to the action
|
||||
</Tooltip>
|
||||
</ToggleButton>
|
||||
<svelte:fragment slot="text">Column</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
{#if userInputEnabled && !input.format?.startsWith('resource-')}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="center"
|
||||
value="user"
|
||||
startIcon={{ icon: faUser }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">User Input</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="right"
|
||||
value="connected"
|
||||
startIcon={{ icon: faArrowRight }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">Connect</svelte:fragment>
|
||||
</Popover>
|
||||
</ToggleButtonGroup>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="right"
|
||||
value="connected"
|
||||
startIcon={{ icon: faArrowRight }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">Connect</svelte:fragment>
|
||||
</Popover>
|
||||
</ToggleButtonGroup>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<InputsSpecEditor
|
||||
hasRows={rowColumns}
|
||||
{id}
|
||||
bind:componentInput={inputSpecs[inputSpecKey]}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<InputsSpecEditor
|
||||
hasRows={rowColumns}
|
||||
{id}
|
||||
bind:componentInput={inputSpecs[inputSpecKey]}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -147,39 +147,6 @@ def main():
|
||||
"y": { "field": "b", "type": "quantitative" },
|
||||
},
|
||||
}
|
||||
`
|
||||
},
|
||||
plotlycomponent: {
|
||||
deno:
|
||||
`
|
||||
export async function main() {
|
||||
return {
|
||||
type: 'bar',
|
||||
x: [1, 2, 3, 4],
|
||||
y: [5, 10, 2, 8],
|
||||
marker: {
|
||||
color: '#C8A2C8',
|
||||
line: {
|
||||
width: 2.5
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
`,
|
||||
python3:
|
||||
`
|
||||
def main():
|
||||
return {
|
||||
"type": "bar",
|
||||
"x": [1, 2, 3, 4],
|
||||
"y": [5, 10, 2, 8],
|
||||
"marker": {
|
||||
"color": "#C8A2C8",
|
||||
"line": {
|
||||
"width": 2.5
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
},
|
||||
piechartcomponent: {
|
||||
|
||||
@@ -25,7 +25,6 @@ export type NumberInputComponent = BaseComponent<'numberinputcomponent'>
|
||||
export type SliderComponent = BaseComponent<'slidercomponent'>
|
||||
export type HtmlComponent = BaseComponent<'htmlcomponent'>
|
||||
export type VegaLiteComponent = BaseComponent<'vegalitecomponent'>
|
||||
export type PlotlyComponent = BaseComponent<'plotlycomponent'>
|
||||
export type TimeseriesComponent = BaseComponent<'timeseriescomponent'>
|
||||
export type ButtonComponent = BaseComponent<'buttoncomponent'> & {
|
||||
recomputeIds: string[] | undefined
|
||||
@@ -108,7 +107,6 @@ export type AppComponent = BaseAppComponent &
|
||||
| FormComponent
|
||||
| FormButtonComponent
|
||||
| VegaLiteComponent
|
||||
| PlotlyComponent
|
||||
)
|
||||
|
||||
export type ComponentSet = {
|
||||
@@ -181,6 +179,4 @@ export type AppEditorContext = {
|
||||
export type EditorMode = 'dnd' | 'preview'
|
||||
export type EditorBreakpoint = 'sm' | 'lg'
|
||||
|
||||
export const IS_APP_PUBLIC_CONTEXT_KEY = 'isAppPublicContext' as const
|
||||
|
||||
type ComponentID = string
|
||||
|
||||
@@ -122,10 +122,6 @@ export const displayData: Record<AppComponent['type'], { name: string; icon: any
|
||||
name: 'Vega Lite',
|
||||
icon: PieChart
|
||||
},
|
||||
plotlycomponent: {
|
||||
name: 'Plotly',
|
||||
icon: PieChart
|
||||
},
|
||||
timeseriescomponent: {
|
||||
name: 'Timeseries',
|
||||
icon: GripHorizontal
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
colorVariants?.[color]?.[variant],
|
||||
variant === 'border' ? 'border' : '',
|
||||
ButtonType.FontSizeClasses[size],
|
||||
ButtonType.SpacingClasses[spacingSize][variant],
|
||||
ButtonType.SpacingClasses[spacingSize],
|
||||
'focus:ring-2 font-semibold',
|
||||
'duration-200 rounded-md',
|
||||
'justify-center items-center text-center whitespace-nowrap inline-flex',
|
||||
@@ -79,8 +79,7 @@
|
||||
target,
|
||||
tabindex: disabled ? -1 : 0,
|
||||
type: buttonType,
|
||||
title,
|
||||
...$$restProps
|
||||
title
|
||||
}
|
||||
|
||||
async function onClick(event: MouseEvent) {
|
||||
|
||||
@@ -20,27 +20,12 @@ export namespace ButtonType {
|
||||
xl: 'text-xl'
|
||||
} as const
|
||||
|
||||
export const SpacingClasses: Record<ButtonType.Size, Record<ButtonType.Variant, string>> = {
|
||||
xs: {
|
||||
border: 'px-3 py-[6px]',
|
||||
contained: 'px-3 py-[7px]'
|
||||
},
|
||||
sm: {
|
||||
border: 'px-3 py-[6px]',
|
||||
contained: 'px-3 py-[7px]'
|
||||
},
|
||||
md: {
|
||||
border: 'px-3 py-[6px]',
|
||||
contained: 'px-3 py-[7px]'
|
||||
},
|
||||
lg: {
|
||||
border: 'px-4 py-[8px]',
|
||||
contained: 'px-4 py-[9px]'
|
||||
},
|
||||
xl: {
|
||||
border: 'px-4 py-[8px]',
|
||||
contained: 'px-4 py-[9px]'
|
||||
},
|
||||
export const SpacingClasses: Record<ButtonType.Size, string> = {
|
||||
xs: 'px-3 py-1.5',
|
||||
sm: 'px-3 py-1.5',
|
||||
md: 'px-3 py-1.5',
|
||||
lg: 'px-4 py-2',
|
||||
xl: 'px-4 py-2'
|
||||
} as const
|
||||
|
||||
export const IconScale: Record<ButtonType.Size, number> = {
|
||||
|
||||
@@ -55,10 +55,8 @@
|
||||
if (open) {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
event.stopImmediatePropagation()
|
||||
open = false
|
||||
event.preventDefault()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
|
||||
import DrawerContent from '$lib/components/common/drawer/DrawerContent.svelte'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { importFlowStore } from '$lib/components/flows/flowStore'
|
||||
import { flowStore, initFlow } from '$lib/components/flows/flowStore'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
|
||||
let drawer: Drawer | undefined = undefined
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
async function importJson() {
|
||||
await goto('/flows/add')
|
||||
$importFlowStore = JSON.parse(pendingJson)
|
||||
Object.assign($flowStore, JSON.parse(pendingJson))
|
||||
|
||||
initFlow($flowStore)
|
||||
drawer?.closeDrawer?.()
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -35,8 +35,9 @@
|
||||
<h2 class="mt-2"
|
||||
>Retries <Tooltip>
|
||||
If defined, upon error this step will be retried with a delay and a maximum number of attempts
|
||||
as defined below. If both static and exponential delay is defined, the static delay attempts
|
||||
are tried before the exponential ones.</Tooltip
|
||||
as defined below. If none of the retries succeed, the step job is a failure and the error will
|
||||
propagate up in the case of a branch, and the error handler will be called ultimately if not
|
||||
handled prior.</Tooltip
|
||||
></h2
|
||||
>
|
||||
|
||||
@@ -75,25 +76,22 @@
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: 'Exponential backoff enabled'
|
||||
right: 'Exponential retry enabled'
|
||||
}}
|
||||
/>
|
||||
{#if flowModule.retry?.exponential}
|
||||
<span class="text-xs font-bold">Attempts</span>
|
||||
<input bind:value={flowModule.retry.exponential.attempts} type="number" />
|
||||
<span class="text-xs font-bold">Mulitplier</span>
|
||||
<span class="text-xs text-gray-500">additional delay = multiplier * base ^ (# attempts)</span>
|
||||
<input bind:value={flowModule.retry.exponential.multiplier} type="number" />
|
||||
<span class="text-xs font-bold">Base</span>
|
||||
<span class="text-xs font-bold">Initial delay (seconds)</span>
|
||||
<input bind:value={flowModule.retry.exponential.seconds} type="number" />
|
||||
{:else}
|
||||
<span class="text-xs font-bold">Attempts</span>
|
||||
<input type="number" disabled />
|
||||
<span class="text-xs font-bold">Mulitplier</span>
|
||||
<span class="text-xs text-gray-500">additional delay = multiplier * seconds ^ (# attempts)</span
|
||||
>
|
||||
<input type="number" disabled />
|
||||
<span class="text-xs font-bold">Base</span>
|
||||
<span class="text-xs font-bold">Initial delay (seconds)</span>
|
||||
<input type="number" disabled />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ export async function loadFlowModuleState(flowModule: FlowModule): Promise<FlowM
|
||||
|
||||
export const idMutex = new Mutex()
|
||||
|
||||
export function getNextId(currentKeys: string[], skipTilde: boolean = false): string {
|
||||
export function getNextId(currentKeys: string[]): string {
|
||||
const max = currentKeys.reduce((acc, key) => {
|
||||
if (key === 'failure' || key.includes('branch') || key.includes('loop')) {
|
||||
return acc
|
||||
|
||||
@@ -6,7 +6,6 @@ import { numberToChars } from './utils'
|
||||
|
||||
export type FlowMode = 'push' | 'pull'
|
||||
|
||||
export const importFlowStore = writable<Flow | undefined>(undefined)
|
||||
export const flowStore = writable<Flow>({
|
||||
summary: '',
|
||||
value: { modules: [] },
|
||||
@@ -54,6 +53,7 @@ export async function initFlow(flow: Flow) {
|
||||
}
|
||||
|
||||
await initFlowState(flow)
|
||||
|
||||
flowStore.set(flow)
|
||||
|
||||
function migrateFlowModule(mod: FlowModule) {
|
||||
|
||||
@@ -162,7 +162,7 @@ export function codeToStaticTemplate(code?: string): string | undefined {
|
||||
if (lines.length == 1) {
|
||||
const line = lines[0].trim()
|
||||
if (line[0] == '`' && line.charAt(line.length - 1) == '`') {
|
||||
return line.slice(1, line.length - 1).replaceAll('\\`', '`')
|
||||
return line.slice(1, line.length - 1)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
@@ -179,10 +179,7 @@ export function emptyFlowModuleState(): FlowModuleState {
|
||||
|
||||
const aCharCode = 'a'.charCodeAt(0)
|
||||
|
||||
export function numberToChars(n: number, skipTilde: boolean = false) {
|
||||
if (n < 0) {
|
||||
return "-" + numberToChars(-n, skipTilde)
|
||||
}
|
||||
export function numberToChars(n: number) {
|
||||
var b = [n],
|
||||
sp,
|
||||
out,
|
||||
@@ -190,12 +187,11 @@ export function numberToChars(n: number, skipTilde: boolean = false) {
|
||||
div
|
||||
|
||||
sp = 0
|
||||
const basisInc = skipTilde ? -1 : 0
|
||||
while (sp < b.length) {
|
||||
if (b[sp] > (25 + basisInc)) {
|
||||
div = Math.floor(b[sp] / (27 + basisInc))
|
||||
if (b[sp] > 25) {
|
||||
div = Math.floor(b[sp] / 27)
|
||||
b[sp + 1] = div - 1
|
||||
b[sp] %= (27 + basisInc)
|
||||
b[sp] %= 27
|
||||
}
|
||||
sp += 1
|
||||
}
|
||||
@@ -203,20 +199,17 @@ export function numberToChars(n: number, skipTilde: boolean = false) {
|
||||
out = ''
|
||||
for (i = 0; i < b.length; i += 1) {
|
||||
let charCode = aCharCode + b[i]
|
||||
out = (b[i] == 26 ? "-" : String.fromCharCode(charCode)) + out
|
||||
out = (charCode == 26 ? '-' : String.fromCharCode(charCode)) + out
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
export function charsToNumber(n: string): number {
|
||||
if (n.charAt(0) == '-') {
|
||||
return charsToNumber(n.slice(1)) * -1
|
||||
}
|
||||
let b = Math.pow(27, n.length - 1)
|
||||
let res = 0
|
||||
for (let c of n) {
|
||||
let charCode = (c == '-' || c == '_') ? aCharCode + 26 : c.charCodeAt(0)
|
||||
let charCode = c == '-' ? aCharCode + 26 : c.charCodeAt(0)
|
||||
res += (charCode - aCharCode + 1) * b
|
||||
b = b / 27
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
return flowModuleToBranch(
|
||||
module,
|
||||
branches,
|
||||
['Default', ...module.value.branches.map((x) => `${truncateRev(x.expr, 20)}`)],
|
||||
['Default', ...module.value.branches.map((x) => `If ${truncateRev(x.expr, 20)}`)],
|
||||
parent,
|
||||
insideLoop
|
||||
)
|
||||
@@ -328,11 +328,11 @@
|
||||
if (!modules.length) {
|
||||
items.push(createVirtualNode(branchParent, 'Empty branch', edgesLabel[i]))
|
||||
} else {
|
||||
modules.forEach((module, j) => {
|
||||
modules.forEach((module) => {
|
||||
const item = getConvertedFlowModule(
|
||||
module,
|
||||
items.length ? items : numberToChars(branch.node.id),
|
||||
j == 0 ? edgesLabel[i] : undefined,
|
||||
edgesLabel[i],
|
||||
insideLoop
|
||||
)
|
||||
item && items.push(item)
|
||||
@@ -434,9 +434,8 @@
|
||||
edgesLabel?: string,
|
||||
offset?: number
|
||||
): Node {
|
||||
const id = -idGenerator.next().value - 1 + (offset ?? 0)
|
||||
return {
|
||||
id,
|
||||
id: -idGenerator.next().value - 1 + (offset ?? 0),
|
||||
position: { x: -1, y: -1 },
|
||||
data: {
|
||||
html: `
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
<table class="w-full">
|
||||
{#each $userWorkspaces as workspace}
|
||||
<tr
|
||||
class="text-xs
|
||||
{$workspaceStore === workspace.id ? 'cursor-default bg-blue-50' : 'cursor-pointer hover:bg-gray-100'}"
|
||||
class="text-xs cursor-pointer hover:bg-gray-100"
|
||||
on:click={() => {
|
||||
if($workspaceStore === workspace.id) { return }
|
||||
switchWorkspace(workspace.id)
|
||||
close()
|
||||
}}
|
||||
|
||||
@@ -151,7 +151,7 @@ export interface DropdownItem {
|
||||
|
||||
export function emptySchema() {
|
||||
return {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema' as string | undefined,
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
properties: {},
|
||||
required: [],
|
||||
type: 'object'
|
||||
|
||||
@@ -74,7 +74,6 @@
|
||||
on_behalf_of_email: $userStore?.email,
|
||||
execution_mode: Policy.execution_mode.PUBLISHER
|
||||
}}
|
||||
fromHub={hubId != null}
|
||||
/>
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import AppEditor from '$lib/components/apps/editor/AppEditor.svelte'
|
||||
import { AppService, AppWithLastVersion } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { page } from '$app/stores'
|
||||
import { decodeState, sendUserToast } from '$lib/utils'
|
||||
import { goto } from '$app/navigation'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
|
||||
|
||||
import FlowBuilder from '$lib/components/FlowBuilder.svelte'
|
||||
import { importFlowStore, initFlow } from '$lib/components/flows/flowStore'
|
||||
import { initFlow } from '$lib/components/flows/flowStore'
|
||||
import { FlowService, type Flow } from '$lib/gen'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { decodeState, emptySchema, sendUserToast } from '$lib/utils'
|
||||
@@ -36,11 +36,7 @@
|
||||
}
|
||||
|
||||
let state = initialState ? decodeState(initialState) : undefined
|
||||
if ($importFlowStore) {
|
||||
flow = $importFlowStore
|
||||
$importFlowStore = undefined
|
||||
sendUserToast('Flow loaded from JSON')
|
||||
} else if (!templatePath && !hubId && state) {
|
||||
if (!templatePath && !hubId && state) {
|
||||
sendUserToast('Flow restored from draft')
|
||||
flow = state.flow
|
||||
state?.selectedId && (selectedId = state?.selectedId)
|
||||
|
||||
@@ -22,8 +22,21 @@
|
||||
|
||||
let selectedId: string = 'settings-graph'
|
||||
|
||||
let flow: Flow = {
|
||||
path: $page.params.path,
|
||||
summary: '',
|
||||
edited_by: '',
|
||||
edited_at: '',
|
||||
value: { modules: [] },
|
||||
archived: false,
|
||||
extra_perms: {},
|
||||
schema: emptySchema()
|
||||
}
|
||||
|
||||
let initialPath: string = ''
|
||||
|
||||
initFlow(flow)
|
||||
|
||||
async function loadFlow(): Promise<void> {
|
||||
loading = true
|
||||
let flow: Flow
|
||||
|
||||
@@ -99,8 +99,7 @@
|
||||
can_write = canWrite(flow.path, flow.extra_perms!, $userStore)
|
||||
}
|
||||
|
||||
$: urlAsync = `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run/f/${flow?.path}`
|
||||
$: urlSync = `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run_wait_result/f/${flow?.path}`
|
||||
$: url = `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run/f/${flow?.path}`
|
||||
|
||||
let runForm: RunForm | undefined
|
||||
let isValid = true
|
||||
@@ -307,39 +306,21 @@
|
||||
></h2
|
||||
>
|
||||
<div class="box max-w-2xl">
|
||||
<div class="flex w-full flex-justify-between mb-1">
|
||||
<div class="flex flex-row gap-x-2 w-full">
|
||||
<a
|
||||
on:click={(e) => {
|
||||
e.preventDefault()
|
||||
copyToClipboard(urlAsync)
|
||||
copyToClipboard(url)
|
||||
}}
|
||||
href={$page.url.protocol + '//' + urlAsync}
|
||||
class="whitespace-nowrap text-ellipsis overflow-hidden mr-1 w-full"
|
||||
href={$page.url.protocol + '//' + url}
|
||||
class="whitespace-nowrap text-ellipsis overflow-hidden mr-1"
|
||||
>
|
||||
{urlAsync}
|
||||
{url}
|
||||
<span class="text-gray-700 ml-2">
|
||||
<Icon data={faClipboard} />
|
||||
</span>
|
||||
</a>
|
||||
<Badge>UUID/Async</Badge>
|
||||
</div>
|
||||
<div class="mb-2 w-full flex flex-justify-between">
|
||||
<a
|
||||
on:click={(e) => {
|
||||
e.preventDefault()
|
||||
copyToClipboard(urlSync)
|
||||
}}
|
||||
href={$page.url.protocol + '//' + urlSync}
|
||||
class="whitespace-nowrap text-ellipsis overflow-hidden mr-1 w-full"
|
||||
>
|
||||
{urlSync}
|
||||
<span class="text-gray-700 ml-2">
|
||||
<Icon data={faClipboard} />
|
||||
</span>
|
||||
</a>
|
||||
<Badge>Result/Sync</Badge>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse">
|
||||
|
||||
<Button size="xs" on:click={userSettings.openDrawer}>Create token</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
import ListFilters from '$lib/components/home/ListFilters.svelte'
|
||||
import SearchItems from '$lib/components/SearchItems.svelte'
|
||||
import autosize from 'svelte-autosize'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { convert } from '@redocly/json-to-json-schema'
|
||||
import Portal from 'svelte-portal'
|
||||
|
||||
type ResourceW = ListableResource & { canWrite: boolean }
|
||||
type ResourceTypeW = ResourceType & { canWrite: boolean }
|
||||
@@ -203,47 +200,10 @@
|
||||
}
|
||||
})
|
||||
|
||||
function openInferrer(): void {
|
||||
inferrer?.openDrawer?.()
|
||||
}
|
||||
|
||||
let disableCustomPrefix = false
|
||||
let tab: 'workspace' | 'types' | 'states' = 'workspace'
|
||||
|
||||
let inferrer: Drawer | undefined = undefined
|
||||
let inferrerJson = ''
|
||||
|
||||
function inferJson(): void {
|
||||
try {
|
||||
newResourceType.schema = {
|
||||
$schema: undefined,
|
||||
required: [],
|
||||
properties: {},
|
||||
...convert(JSON.parse(inferrerJson))
|
||||
}
|
||||
} catch (e) {
|
||||
sendUserToast(`Invalid JSON: ${e}`, true)
|
||||
}
|
||||
inferrer?.closeDrawer?.()
|
||||
}
|
||||
</script>
|
||||
|
||||
<Portal>
|
||||
<Drawer bind:this={inferrer} size="800px">
|
||||
<DrawerContent title="Import app from JSON" on:close={() => inferrer?.toggleDrawer?.()}>
|
||||
<SimpleEditor
|
||||
bind:code={inferrerJson}
|
||||
lang="json"
|
||||
class="h-full"
|
||||
fixedOverflowWidgets={false}
|
||||
/>
|
||||
<svelte:fragment slot="actions">
|
||||
<Button size="sm" on:click={inferJson}>Infer</Button>
|
||||
</svelte:fragment>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Portal>
|
||||
|
||||
<Drawer bind:this={resourceTypeViewer} size="800px">
|
||||
<DrawerContent title={resourceTypeViewerObj.rt} on:close={resourceTypeViewer.closeDrawer}>
|
||||
<div>
|
||||
@@ -299,11 +259,6 @@
|
||||
>
|
||||
<div>
|
||||
<div class="mb-1 font-semibold text-gray-700">Schema</div>
|
||||
<div class="mb-2 w-full flex flex-row-reverse">
|
||||
<Button on:click={openInferrer} size="sm" color="dark" variant="border"
|
||||
>Infer schema from a json value</Button
|
||||
>
|
||||
</div>
|
||||
<SchemaEditor bind:schema={newResourceType.schema} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -445,8 +445,8 @@
|
||||
</h3>
|
||||
<Skeleton {loading} layout={[[8.5]]} />
|
||||
<Tabs selected="uuid">
|
||||
<Tab value="uuid">UUID/Async</Tab>
|
||||
<Tab value="result">Result/Sync</Tab>
|
||||
<Tab value="uuid">UUID</Tab>
|
||||
<Tab value="result">Result</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
{#each Object.keys(webhooks) as key}
|
||||
<TabContent value={key}>
|
||||
|
||||
@@ -7,15 +7,9 @@
|
||||
Script
|
||||
} from '$lib/gen'
|
||||
import type { User } from '$lib/gen'
|
||||
import { sendUserToast, isCloudHosted, capitalize } from '$lib/utils'
|
||||
import { sendUserToast, isCloudHosted } from '$lib/utils'
|
||||
import PageHeader from '$lib/components/PageHeader.svelte'
|
||||
import {
|
||||
superadmin,
|
||||
usageStore,
|
||||
userStore,
|
||||
usersWorkspaceStore,
|
||||
workspaceStore
|
||||
} from '$lib/stores'
|
||||
import { superadmin, userStore, usersWorkspaceStore, workspaceStore } from '$lib/stores'
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { faSlack } from '@fortawesome/free-brands-svg-icons'
|
||||
import TableCustom from '$lib/components/TableCustom.svelte'
|
||||
@@ -47,9 +41,14 @@
|
||||
let nbDisplayed = 30
|
||||
let plan: string | undefined = undefined
|
||||
let customer_id: string | undefined = undefined
|
||||
let webhook: string | undefined = undefined
|
||||
let tab =
|
||||
($page.url.searchParams.get('tab') as 'users' | 'slack' | 'premium' | 'export_delete') ??
|
||||
'users'
|
||||
($page.url.searchParams.get('tab') as
|
||||
| 'users'
|
||||
| 'slack'
|
||||
| 'premium'
|
||||
| 'export_delete'
|
||||
| 'webhook') ?? 'users'
|
||||
|
||||
// function getDropDownItems(username: string): DropdownItem[] {
|
||||
// return [
|
||||
@@ -84,6 +83,14 @@
|
||||
sendUserToast(`slack command script set to ${scriptPath}`)
|
||||
}
|
||||
|
||||
async function editWebhook(): Promise<void> {
|
||||
await WorkspaceService.editWebhook({
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: { webhook }
|
||||
})
|
||||
sendUserToast(`webhook set to ${webhook}`)
|
||||
}
|
||||
|
||||
async function loadSettings(): Promise<void> {
|
||||
const settings = await WorkspaceService.getSettings({ workspace: $workspaceStore! })
|
||||
team_name = settings.slack_name
|
||||
@@ -93,6 +100,7 @@
|
||||
plan = settings.plan
|
||||
customer_id = settings.customer_id
|
||||
initialPath = scriptPath
|
||||
webhook = settings.webhook
|
||||
}
|
||||
|
||||
async function listUsers(): Promise<void> {
|
||||
@@ -184,24 +192,25 @@
|
||||
{#if $userStore?.is_admin || $superadmin}
|
||||
<PageHeader title="Workspace Settings of {$workspaceStore}" />
|
||||
|
||||
<div class="overflow-x-auto scrollbar-hidden">
|
||||
<Tabs bind:selected={tab}>
|
||||
<Tab size="md" value="users">
|
||||
<div class="flex gap-2 items-center my-1"> Users & Invites </div>
|
||||
<Tabs bind:selected={tab}>
|
||||
<Tab size="md" value="users">
|
||||
<div class="flex gap-2 items-center my-1"> Users & Invites </div>
|
||||
</Tab>
|
||||
<Tab size="md" value="slack">
|
||||
<div class="flex gap-2 items-center my-1"> Slack Command </div>
|
||||
</Tab>
|
||||
{#if isCloudHosted()}
|
||||
<Tab size="md" value="premium">
|
||||
<div class="flex gap-2 items-center my-1"> Premium Plans </div>
|
||||
</Tab>
|
||||
<Tab size="md" value="slack">
|
||||
<div class="flex gap-2 items-center my-1"> Slack Command </div>
|
||||
</Tab>
|
||||
{#if isCloudHosted()}
|
||||
<Tab size="md" value="premium">
|
||||
<div class="flex gap-2 items-center my-1"> Premium Plans </div>
|
||||
</Tab>
|
||||
{/if}
|
||||
<Tab size="md" value="export_delete">
|
||||
<div class="flex gap-2 items-center my-1"> Export & Delete Workspace </div>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
{/if}
|
||||
<Tab size="md" value="export_delete">
|
||||
<div class="flex gap-2 items-center my-1"> Export & Delete Workspace </div>
|
||||
</Tab>
|
||||
<Tab size="md" value="webhook">
|
||||
<div class="flex gap-2 items-center my-1">Webhook for CLI Sync</div>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
{#if tab == 'users'}
|
||||
<PageHeader title="Members ({users?.length ?? ''})" primary={false} />
|
||||
|
||||
@@ -244,7 +253,7 @@
|
||||
<ToggleButtonGroup
|
||||
selected={is_admin ? 'admin' : operator ? 'operator' : 'author'}
|
||||
on:selected={async (e) => {
|
||||
if (is_admin && email == $userStore?.email && e.detail != 'admin') {
|
||||
if (is_admin && e.detail != 'admin') {
|
||||
sendUserToast(
|
||||
'Admins cannot be demoted by themselves, ask another admin to demote you',
|
||||
true
|
||||
@@ -433,7 +442,7 @@
|
||||
{#if isCloudHosted()}
|
||||
<div class="mt-4" />
|
||||
{#if customer_id}
|
||||
<div class="mt-2 mb-2">
|
||||
<div class="mt-2 mb-6">
|
||||
<Button
|
||||
endIcon={{ icon: faExternalLink }}
|
||||
href="/api/w/{$workspaceStore}/workspaces/billing_portal">Customer Portal</Button
|
||||
@@ -444,58 +453,33 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="text-sm mb-4 box p-2 max-w-3xl">
|
||||
<div class="text-sm mb-4">
|
||||
{#if premium_info?.premium}
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div
|
||||
>Current plan: <div class=" inline text-2xl font-bold">{plan ?? 'Free plan'}</div
|
||||
></div
|
||||
>
|
||||
{#if plan}
|
||||
<div class="mb-2"
|
||||
><div class=" inline text-2xl font-bold float-right"
|
||||
>{capitalize(plan ?? 'free')} plan</div
|
||||
></div
|
||||
>
|
||||
{:else}
|
||||
<div class="inline text-2xl font-bold ">Free plan</div>
|
||||
{/if}
|
||||
|
||||
{#if plan}
|
||||
{@const team_factor = plan == 'team' ? 8 : 32}
|
||||
{@const user_nb = Math.max(0, (users?.filter((x) => !x.operator).length ?? 0) - 1)}
|
||||
{@const team_factor = plan == 'team' ? 10 : 50}
|
||||
{@const max = (users?.length ?? 0) * team_factor}
|
||||
|
||||
<div>
|
||||
Extra seats:
|
||||
<div class="inline text-2xl font-bold float-right"
|
||||
>{user_nb} * ${team_factor}
|
||||
= ${(users?.length ?? 0) * team_factor}/mo</div
|
||||
Current number of seats in this workspace:
|
||||
<div class="inline text-2xl font-bold"
|
||||
>{users?.length ?? 0} * ${team_factor} = ${(users?.length ?? 0) *
|
||||
team_factor}/mo</div
|
||||
>
|
||||
<Tooltip
|
||||
>Actual pricing is calculated on the MAXIMUM number of users in a given billing
|
||||
period, see the customer portal for more info.</Tooltip
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Extra operators:
|
||||
<div class="inline text-2xl font-bold float-right"
|
||||
>{Math.max(0, (users?.filter((x) => x.operator).length ?? 0) - 1)} * ${team_factor /
|
||||
2} = ${((users?.length ?? 0) * team_factor) / 2}/mo</div
|
||||
>
|
||||
<Tooltip
|
||||
>Actual pricing is calculated on the MAXIMUM number of users in a given billing
|
||||
period, see the customer portal for more info.</Tooltip
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
Computations executed this month:
|
||||
<div class=" inline text-2xl font-bold float-right"
|
||||
>{premium_info?.usage ?? 0}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
Extra computations (above the 10k included) this month:
|
||||
<div class=" inline text-2xl font-bold float-right"
|
||||
>{Math.max(0, (premium_info?.usage ?? 0) - 10000)} x {plan == 'team'
|
||||
? '0.001'
|
||||
: '0.004'} = ${Math.max(0, (premium_info?.usage ?? 0) - 10000) *
|
||||
(plan == 'team' ? 0.001 : 0.004)}
|
||||
Included number of executions based on your seats and plan:
|
||||
<div class=" inline text-2xl font-bold"
|
||||
>{users?.length ?? 0} seats x {plan == 'team' ? '10k' : '50k'} = {max}k
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -539,8 +523,8 @@
|
||||
{#if planTitle == 'Team'}
|
||||
{#if plan != 'team'}
|
||||
<div class="mt-4 mx-auto">
|
||||
<Button href="/api/w/{$workspaceStore}/workspaces/checkout?plan=team"
|
||||
>Upgrade to the Team plan</Button
|
||||
<Button disabled href="/api/w/{$workspaceStore}/workspaces/checkout?plan=team"
|
||||
>Upgrade to the Team plan (Coming soon)</Button
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
@@ -685,6 +669,29 @@
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if tab == 'webhook'}
|
||||
<PageHeader title="Webhook for CLI Sync" primary={false} />
|
||||
|
||||
<div class="mt-2"
|
||||
><Alert type="info" title="Send events to an external service"
|
||||
>Connect your windmill workspace to an external service to sync or get notified about any
|
||||
changes</Alert
|
||||
></div
|
||||
>
|
||||
|
||||
<h3 class="mt-5 text-gray-700"
|
||||
>URL to send requests to<Tooltip>
|
||||
This URL will be POSTed to with a JSON body depending on the type of event. The type is
|
||||
indicated by the <pre>type</pre> field. The other fields are dependent on the type.
|
||||
</Tooltip>
|
||||
</h3>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<input class="justify-start" type="text" bind:value={webhook} />
|
||||
<Button color="blue" btnClasses="justify-end" size="md" on:click={editWebhook}
|
||||
>Set Webhook</Button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4 m-4" role="alert">
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
let interval = setInterval(async () => {
|
||||
attempt += 1
|
||||
if ((await WorkspaceService.getSettings({ workspace: $workspaceStore! })).customer_id) {
|
||||
clearInterval(interval)
|
||||
goto('/workspace_settings?tab=premium')
|
||||
} else if (attempt > 10) {
|
||||
sendUserToast('Subscription upgrade failed. Contact contact@windmill.dev', true)
|
||||
@@ -42,9 +41,7 @@
|
||||
You will be redirected to the workspace settings page in 5 seconds...
|
||||
</p>
|
||||
{:else}
|
||||
<p class="text-sm my-6 text-gray-600 w-full text-center">
|
||||
Waiting for your upgrade to be processed...
|
||||
</p>
|
||||
<p class="text-sm my-6 text-gray-600"> Waiting for your upgrade to be processed... </p>
|
||||
{/if}
|
||||
|
||||
<div class="block m-auto w-20">
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
import { browser } from '$app/environment'
|
||||
import { page } from '$app/stores'
|
||||
import AppPreview from '$lib/components/apps/editor/AppPreview.svelte'
|
||||
import { IS_APP_PUBLIC_CONTEXT_KEY, type EditorBreakpoint } from '$lib/components/apps/types'
|
||||
import type { EditorBreakpoint } from '$lib/components/apps/types'
|
||||
|
||||
import { Alert, Skeleton } from '$lib/components/common'
|
||||
import { WindmillIcon } from '$lib/components/icons'
|
||||
import { AppService, AppWithLastVersion, GlobalUserInfo, UserService } from '$lib/gen'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { setContext } from 'svelte'
|
||||
import github from 'svelte-highlight/styles/github'
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
@@ -16,8 +15,6 @@
|
||||
let user: GlobalUserInfo | undefined = undefined
|
||||
let notExists = false
|
||||
|
||||
setContext(IS_APP_PUBLIC_CONTEXT_KEY, true)
|
||||
|
||||
async function loadApp() {
|
||||
try {
|
||||
app = await AppService.getPublicAppBySecret({
|
||||
|
||||
@@ -4,8 +4,8 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
wmill = ">=1.61.1"
|
||||
wmill_pg = ">=1.61.1"
|
||||
wmill = ">=1.60.0"
|
||||
wmill_pg = ">=1.60.0"
|
||||
sendgrid = "*"
|
||||
mysql-connector-python = "*"
|
||||
pymongo = "*"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.61.1
|
||||
version: 1.60.0
|
||||
title: OpenFlow Spec
|
||||
contact:
|
||||
name: Ruben Fiszel
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
description = "A client library for accessing Windmill server wrapping the Windmill client API"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
@@ -16,7 +16,7 @@ include = ["wmill/py.typed"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
windmill-api = "^1.61.1"
|
||||
windmill-api = "^1.60.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=1.0.2", "poetry-dynamic-versioning"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "wmill-pg"
|
||||
version = "1.61.1"
|
||||
version = "1.60.0"
|
||||
description = "An extension client for the wmill client library focused on pg"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.61.1
|
||||
1.60.0
|
||||
|
||||
Reference in New Issue
Block a user