Compare commits

...

150 Commits

Author SHA1 Message Date
Ruben Fiszel
9007072274 all 2025-03-04 15:24:10 +01:00
Ruben Fiszel
fba9e7ef03 fix: improve cancel performance 2025-03-03 23:50:13 +01:00
Ruben Fiszel
72109b01d7 whitelabel improvements (#5405)
* hide resource

* more customizations

* disable tooltips globally & hide other elemetns

* hide variable picker in autogenerated ui too

* change to disableX and context

* all

* all

* all

* all

* all

* all

* fix

* fix

* fix

---------

Co-authored-by: smuun <silas@athenaintelligence.ai>
2025-03-03 22:35:05 +01:00
pyranota
e7428bf84d nit: Pip index url -> UV index url (#5410) 2025-03-03 20:59:21 +01:00
Ruben Fiszel
56b417c669 chore(main): release 1.473.0 (#5399)
* chore(main): release 1.473.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-03-03 15:18:06 +01:00
Ruben Fiszel
8e1e37bf9e improve menu a hrefs 2025-03-03 14:58:49 +01:00
Guilhem
5e965aec15 prevent modal from closing when clicking inside popover (#5406) 2025-03-03 14:57:34 +01:00
pyranota
04ffbf8c26 fix: remove typings_extensions from python sdk
* fix: make python-client compatible with python >= 3.13

* remove completely

* remove sys import
2025-03-03 14:56:52 +01:00
Ruben Fiszel
b601883bc0 fix sqlx 2025-03-03 14:51:51 +01:00
Ruben Fiszel
81ed965812 make PG_SCHEMA appear in logs 2025-03-03 14:44:03 +01:00
Ruben Fiszel
e1ff00117c fix: improve db loads by adding index on audit 2025-03-03 14:23:35 +01:00
Ruben Fiszel
55d599d4b6 add PG_SCHEMA support 2025-03-03 11:25:20 +01:00
HugoCasa
46c784574a feat: app s3 input anonymous delete (#5401)
* feat: app s3 input anonymous delete

* tmp ee ref

* fix build
2025-02-27 16:28:56 +01:00
Ruben Fiszel
3063001491 fix: migrations do not refer to public schema anymore (#5400) 2025-02-27 14:37:39 +01:00
HugoCasa
d30979d04e hub script fetch retry (#5379)
* hub script fetch retry

* use backon

* oups

* Update backend/windmill-common/src/scripts.rs

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* retry whole logic

* nits

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-27 11:29:14 +01:00
HugoCasa
7bf9e25ede feat: track workspace runnables used in flows (#5369)
* feat: track workspace runnables used in flows

* track script hash

* weird

* do it with lock

* Revert "feat: add support for | None and Optional in python (#5361)"

This reverts commit 9736355d5f.

* Revert "Revert "feat: add support for | None and Optional in python (#5361)""

This reverts commit bb8f709894.

* update openapi

* delete old in lock_modules + don't track hub scripts
2025-02-27 10:01:12 +01:00
Ruben Fiszel
f406da9976 recover previous step in more cases in flow 2025-02-26 23:40:05 +01:00
Ruben Fiszel
07f91af535 chore(main): release 1.472.1 (#5397)
* chore(main): release 1.472.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-26 21:45:51 +01:00
HugoCasa
cb559d6083 fix: disable bundling using env var (#5396) 2025-02-26 21:41:49 +01:00
Ruben Fiszel
63af3ce0b1 chore(main): release 1.472.0 (#5393) 2025-02-26 19:29:22 +01:00
Ruben Fiszel
3bc891a0dd fix compile 2025-02-26 19:23:55 +01:00
Ruben Fiszel
5569e4d495 fix: downgrade v8 to fix some rare panics 2025-02-26 19:12:24 +01:00
Alexander Petric
7f290bbf6a fix(frontend): markdown shows single backtick in single line code block (#5391) 2025-02-26 17:35:10 +01:00
Guilhem
69fc8a98ae feat(frontend): migrate toggle to melt (4/4) (#5329)
* use melt menu in sidebar

* stop keyboard navigation for disabled items

* use melt menu for FavoriteMenu and WorkspaceMenu

* fix popover placement for menuButton

* use melt menu for operator menu

* fix notification

* fix operator menu

* Use melt menu in FlowJobsMenu

* use melt menu for AppMenu

* clean code

* clean code

* add use clickOutside option to Menu

* use pointerdown_outside

* use pointerdown_outside

# Conflicts:
#	frontend/src/lib/components/meltComponents/Menu.svelte

* use pointerdown in menus

* add max-h to app dropdown menu

* keep more open in operator menu

* add a MenuItem component

* clean

* nit

* nit

* clean code

* put conditionalMelt as utility function

* remove unused Portal

* Add debounce effect in operator menu

* fix component jumping due to z-index

* format pages

* migrate dropdown to melt

* migrate toggle to melt

* migrate popup to melt popover

* fix missing toggle item

* feat: remove `pip` fallback option for python and ansible (#5186)

* refactor!: Remove `pip` fallback option for python and ansible

BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15)

* fix errors in main.rs

* fix tests

* remove nsjail for pip

* fix imports

* fix compilation error

* reinforce melt types

* fix racing condition issue in closing operator menu

* nit

* fix id conflix with melt element

* nit

* clean code

* use melt dropdown instead of menubar

* prevent modal from closing on click outside button in menu

* Apply automatic changes

* fix nit

* nit

* close dropdown when opening a new one

* replace MenuV2 with melt Menu (1/4) (#5214)

* use melt menu in sidebar

* stop keyboard navigation for disabled items

* use melt menu for FavoriteMenu and WorkspaceMenu

* fix popover placement for menuButton

* use melt menu for operator menu

* fix notification

* fix operator menu

* Use melt menu in FlowJobsMenu

* use melt menu for AppMenu

* clean code

* clean code

* add use clickOutside option to Menu

* use pointerdown_outside

* use pointerdown_outside

# Conflicts:
#	frontend/src/lib/components/meltComponents/Menu.svelte

* use pointerdown in menus

* add max-h to app dropdown menu

* keep more open in operator menu

* add a MenuItem component

* clean

* nit

* nit

* clean code

* put conditionalMelt as utility function

* remove unused Portal

* Add debounce effect in operator menu

* fix component jumping due to z-index

* feat: remove `pip` fallback option for python and ansible (#5186)

* refactor!: Remove `pip` fallback option for python and ansible

BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15)

* fix errors in main.rs

* fix tests

* remove nsjail for pip

* fix imports

* fix compilation error

* reinforce melt types

* fix racing condition issue in closing operator menu

* nit

* fix id conflix with melt element

* nit

* prevent modal from closing on click outside button in menu

---------

Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
# Conflicts:
#	frontend/src/lib/components/meltComponents/MenuItem.svelte
#	frontend/src/lib/utils.ts

* clean

* fix z index and render

* fix initialize of dropdownmenu after melt migration

* feat: add support for | None and Optional in python (#5361)

* feat: add support for | None and Optional in python

* update python parser package

* add local rooting for MenuItem

* fix z index

* clean

* nit

* nit

* clean code

* nit

* nit

* clean code

* reinforce melt types

* wip

* reiforce instance select types for toggleButton

* nit

* fix double event

* fix selectedTable toggle

* fix sqs toggleButton

* fix potential issue with binding in toggleGroup

* Update frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: HugoCasa <hugo@casademont.ch>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-26 17:32:40 +01:00
Alexander Petric
eff2a4c496 set rust version for windows build (#5392)
* set rust version for windows build

* set rust version for windows build

* correct ation
2025-02-26 17:32:18 +01:00
Guilhem
5219062cc1 fix row picker (#5390) 2025-02-26 15:27:00 +01:00
Ruben Fiszel
318b654106 chore(main): release 1.471.1 (#5389)
* chore(main): release 1.471.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-26 13:07:47 +01:00
Guilhem
731299ee14 fix(frontend) load primary schedule args in detail trigger page (#5388)
* load primary schedule args in detail trigger page

* nit
2025-02-26 12:54:31 +01:00
Ruben Fiszel
dde3c5bef3 fix compile issue 2025-02-26 12:51:11 +01:00
Ruben Fiszel
3ada264c4a fix: update to rust 1.86.0 2025-02-26 11:34:28 +01:00
Ruben Fiszel
e2cd8dbdf0 chore(main): release 1.471.0 (#5385)
* chore(main): release 1.471.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-26 11:06:07 +01:00
HugoCasa
487d84bd7f feat: add support for claude sonnet 3.7 thinking (#5387)
* feat: add support for claude sonnet 3.7 thinking

* non streaming as well
2025-02-26 10:49:05 +01:00
Ruben Fiszel
82d37d6ace further reactivity for apps improvements 2025-02-26 10:23:15 +01:00
Guilhem
a85ebfbbf4 fix(frontend): improve pagination handling and filter refreshes (#5378)
* fix pagination handling and filter refreshes

* wip

* fix window navigation
2025-02-26 09:42:00 +01:00
Ruben Fiszel
33b0e71523 chore(main): release 1.470.1 (#5383)
* chore(main): release 1.470.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-26 05:35:17 +01:00
Ruben Fiszel
630e54f65c fix: multiple app initializations fixes 2025-02-26 05:31:42 +01:00
Ruben Fiszel
b26ebb3a79 chore(main): release 1.470.0 (#5381)
* chore(main): release 1.470.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-26 05:13:15 +01:00
Ruben Fiszel
9b3ec10c12 improve markdown styling 2025-02-26 05:08:00 +01:00
Ruben Fiszel
ebe3582ced fix backticks handling in template 2025-02-26 04:59:56 +01:00
Ruben Fiszel
24b6003780 fix: multiple app initializations fixes 2025-02-26 04:44:14 +01:00
Alexander Petric
478d3fbf4a feat(frontend): set default app refesh interval (#5380) 2025-02-25 23:21:36 +01:00
Ruben Fiszel
47c8b334ef chore(main): release 1.469.0 (#5377)
* chore(main): release 1.469.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-25 21:51:55 +01:00
Ruben Fiszel
44b26d2cce fix: improve flow editor for vscode extension 2025-02-25 21:42:54 +01:00
Ruben Fiszel
4ab622deaa nits 2025-02-25 20:36:52 +01:00
Ruben Fiszel
c13fa65354 fix nit 2025-02-25 20:00:03 +01:00
Ruben Fiszel
56d1da78fd fix: improve infinite grid behavior 2025-02-25 19:51:41 +01:00
Ruben Fiszel
d0ee16b1b9 better table action rendering 2025-02-25 19:13:03 +01:00
Ruben Fiszel
b175730324 improve delete component of tables 2025-02-25 17:57:31 +01:00
Ruben Fiszel
874dbd9dfa fix actions refresh 2025-02-25 17:32:28 +01:00
pyranota
25f9369d5e fix dedicated worker multipython (#5338)
* fix dedicated worker multipython

* fix typo

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix dedublicate logic

* fix ellipsis complaints

* more factorization

* pass slice instead of ref to vector

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-02-25 17:22:03 +01:00
Ruben Fiszel
64d0c32443 run button paddingnits 2025-02-25 17:17:25 +01:00
Le Phat Tan
50607c7625 feat: python-client now support mocked api via WM_MOCKED_API_FILE env (#5372)
* feat: python-client now support mocked api via `WM_MOCKED_API_FILE` env

* fix: typo
2025-02-25 16:39:32 +01:00
Ruben Fiszel
c8a959691c feat: limit the number of times a job can be restarted (3) after loss of pings 2025-02-25 16:35:29 +01:00
Guilhem
edcf2d43a2 add catch (#5375) 2025-02-25 14:36:12 +01:00
Guilhem
3bf0bc64af check password input type (#5374) 2025-02-25 12:50:45 +01:00
Guilhem
d48b2dd886 migrate popup to melt popover (3/4) (#5328)
* use melt menu in sidebar

* stop keyboard navigation for disabled items

* use melt menu for FavoriteMenu and WorkspaceMenu

* fix popover placement for menuButton

* use melt menu for operator menu

* fix notification

* fix operator menu

* Use melt menu in FlowJobsMenu

* use melt menu for AppMenu

* clean code

* clean code

* add use clickOutside option to Menu

* use pointerdown_outside

* use pointerdown_outside

# Conflicts:
#	frontend/src/lib/components/meltComponents/Menu.svelte

* use pointerdown in menus

* add max-h to app dropdown menu

* keep more open in operator menu

* add a MenuItem component

* clean

* nit

* nit

* clean code

* put conditionalMelt as utility function

* remove unused Portal

* Add debounce effect in operator menu

* fix component jumping due to z-index

* format pages

* migrate dropdown to melt

* migrate popup to melt popover

* feat: remove `pip` fallback option for python and ansible (#5186)

* refactor!: Remove `pip` fallback option for python and ansible

BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15)

* fix errors in main.rs

* fix tests

* remove nsjail for pip

* fix imports

* fix compilation error

* reinforce melt types

* fix racing condition issue in closing operator menu

* nit

* fix id conflix with melt element

* nit

* clean code

* use melt dropdown instead of menubar

* prevent modal from closing on click outside button in menu

* fix nit

* nit

* close dropdown when opening a new one

* replace MenuV2 with melt Menu (1/4) (#5214)

* use melt menu in sidebar

* stop keyboard navigation for disabled items

* use melt menu for FavoriteMenu and WorkspaceMenu

* fix popover placement for menuButton

* use melt menu for operator menu

* fix notification

* fix operator menu

* Use melt menu in FlowJobsMenu

* use melt menu for AppMenu

* clean code

* clean code

* add use clickOutside option to Menu

* use pointerdown_outside

* use pointerdown_outside

# Conflicts:
#	frontend/src/lib/components/meltComponents/Menu.svelte

* use pointerdown in menus

* add max-h to app dropdown menu

* keep more open in operator menu

* add a MenuItem component

* clean

* nit

* nit

* clean code

* put conditionalMelt as utility function

* remove unused Portal

* Add debounce effect in operator menu

* fix component jumping due to z-index

* feat: remove `pip` fallback option for python and ansible (#5186)

* refactor!: Remove `pip` fallback option for python and ansible

BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15)

* fix errors in main.rs

* fix tests

* remove nsjail for pip

* fix imports

* fix compilation error

* reinforce melt types

* fix racing condition issue in closing operator menu

* nit

* fix id conflix with melt element

* nit

* prevent modal from closing on click outside button in menu

---------

Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
# Conflicts:
#	frontend/src/lib/components/meltComponents/MenuItem.svelte
#	frontend/src/lib/utils.ts

* clean

* fix z index and render

* fix initialize of dropdownmenu after melt migration

* feat: add support for | None and Optional in python (#5361)

* feat: add support for | None and Optional in python

* update python parser package

* add local rooting for MenuItem

* fix z index

* clean

* nit

* nit

* clean code

* nit

---------

Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: HugoCasa <hugo@casademont.ch>
2025-02-25 09:53:43 +01:00
Ruben Fiszel
03f6db0cb8 chore(main): release 1.468.0 (#5356)
* chore(main): release 1.468.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-24 23:14:49 +01:00
Ruben Fiszel
4ee4ff78d3 fix: improve custom component rendering 2025-02-24 22:43:36 +01:00
Ruben Fiszel
d45c1f69d4 fix: handle better optional chaining operator 2025-02-24 20:08:13 +01:00
Ruben Fiszel
96597d3d6b fix: improve app markdown rendering 2025-02-24 19:33:14 +01:00
Henri Courdent
9a236ef3eb Changelogs 24 feb (#5363) 2025-02-24 19:01:09 +01:00
Ruben Fiszel
8806870b1b fix: add LOCALAPPDATA env variable to python execution on windows 2025-02-24 18:36:26 +01:00
Ruben Fiszel
11881b48cc nit 2025-02-24 17:53:46 +01:00
Ruben Fiszel
61983a5bbf fix confirmation modal 2025-02-24 17:50:54 +01:00
Ruben Fiszel
0456272e3f fix: improve webhook settings cache invalidation 2025-02-24 16:10:53 +01:00
Ruben Fiszel
1d03a95bef store auto-refresh setting in local storage 2025-02-24 15:47:06 +01:00
Ruben Fiszel
3028325615 fix: fix confirmation modal check on deploy 2025-02-24 15:42:55 +01:00
HugoCasa
b3e00b7fdc feat: add audit logs scope filter in admins workspace (#5352)
* feat: add audit logs scope filter in admins workspace

* fix build

* disallow creating a workspace named global

* Update ee-repo-ref.txt
2025-02-24 15:25:28 +01:00
Ruben Fiszel
653241c43e unify variable add 2025-02-24 15:16:50 +01:00
Ruben Fiszel
7c842c88bf fix: handle better forced value propagation in apps 2025-02-24 15:16:33 +01:00
Guilhem
d7ef7fe360 migrate dropdown melt (2/4) (#5327)
* use melt menu in sidebar

* stop keyboard navigation for disabled items

* use melt menu for FavoriteMenu and WorkspaceMenu

* fix popover placement for menuButton

* use melt menu for operator menu

* fix notification

* fix operator menu

* Use melt menu in FlowJobsMenu

* use melt menu for AppMenu

* clean code

* clean code

* add use clickOutside option to Menu

* use pointerdown_outside

* use pointerdown_outside

# Conflicts:
#	frontend/src/lib/components/meltComponents/Menu.svelte

* use pointerdown in menus

* add max-h to app dropdown menu

* keep more open in operator menu

* add a MenuItem component

* clean

* nit

* nit

* clean code

* put conditionalMelt as utility function

* remove unused Portal

* Add debounce effect in operator menu

* fix component jumping due to z-index

* format pages

* migrate dropdown to melt

* feat: remove `pip` fallback option for python and ansible (#5186)

* refactor!: Remove `pip` fallback option for python and ansible

BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15)

* fix errors in main.rs

* fix tests

* remove nsjail for pip

* fix imports

* fix compilation error

* reinforce melt types

* fix racing condition issue in closing operator menu

* nit

* fix id conflix with melt element

* nit

* clean code

* use melt dropdown instead of menubar

* prevent modal from closing on click outside button in menu

* fix nit

* nit

* close dropdown when opening a new one

* clean

* fix z index and render

---------

Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-02-24 14:53:50 +01:00
Ruben Fiszel
a87b4a52ed nit saml 2025-02-24 14:43:27 +01:00
HugoCasa
9736355d5f feat: add support for | None and Optional in python (#5361)
* feat: add support for | None and Optional in python

* update python parser package
2025-02-24 14:12:29 +01:00
Ruben Fiszel
0329d91ee9 fix initialize of dropdownmenu after melt migration 2025-02-24 13:16:40 +01:00
Guilhem
7ef8100250 replace MenuV2 with melt Menu (1/4) (#5214)
* use melt menu in sidebar

* stop keyboard navigation for disabled items

* use melt menu for FavoriteMenu and WorkspaceMenu

* fix popover placement for menuButton

* use melt menu for operator menu

* fix notification

* fix operator menu

* Use melt menu in FlowJobsMenu

* use melt menu for AppMenu

* clean code

* clean code

* add use clickOutside option to Menu

* use pointerdown_outside

* use pointerdown_outside

# Conflicts:
#	frontend/src/lib/components/meltComponents/Menu.svelte

* use pointerdown in menus

* add max-h to app dropdown menu

* keep more open in operator menu

* add a MenuItem component

* clean

* nit

* nit

* clean code

* put conditionalMelt as utility function

* remove unused Portal

* Add debounce effect in operator menu

* fix component jumping due to z-index

* feat: remove `pip` fallback option for python and ansible (#5186)

* refactor!: Remove `pip` fallback option for python and ansible

BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15)

* fix errors in main.rs

* fix tests

* remove nsjail for pip

* fix imports

* fix compilation error

* reinforce melt types

* fix racing condition issue in closing operator menu

* nit

* fix id conflix with melt element

* nit

* prevent modal from closing on click outside button in menu

---------

Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-02-24 10:28:06 +01:00
Ruben Fiszel
fd1cfc0df5 bench.sh 2025-02-24 01:20:20 +01:00
Alexander Petric
f1c5b77d7a fix(frontend): make html app component content selectable (#5359) 2025-02-23 23:49:54 +01:00
Ruben Fiszel
089ba7ae00 fix npn check 2025-02-23 23:49:33 +01:00
Ruben Fiszel
66451d4da1 recycle audit logs 2025-02-23 23:38:23 +01:00
Ruben Fiszel
1a54e1ed45 delete audit logs stub older than 14days on CE 2025-02-23 23:33:47 +01:00
Ruben Fiszel
692de3e628 update bun to 1.2.3 2025-02-23 23:11:07 +01:00
Ruben Fiszel
f90841ac5a fix missing lock error logs 2025-02-23 09:18:50 +01:00
Ruben Fiszel
c81a13cdac bun to 1.2.2 while 1.2.3 is not released 2025-02-22 16:31:00 +01:00
Ruben Fiszel
05659816e7 fix: improve cancel/back behavior on editors 2025-02-22 16:28:28 +01:00
Ruben Fiszel
7c0152c353 add runs page links to history section 2025-02-22 15:22:53 +01:00
Ruben Fiszel
b8e6d0da79 feat: make flow lock deployment error visible in UI 2025-02-22 15:02:16 +01:00
Ruben Fiszel
20547493e0 add PRINT_NATIVE_ERRORS env variable 2025-02-22 11:06:42 +01:00
Ruben Fiszel
c6dbd239b4 update deno_core implementation to latest 2.2.1 2025-02-22 11:04:54 +01:00
Ruben Fiszel
b102ff4a46 fix: update deno 2.1.2->2.2.1 2025-02-22 09:25:47 +01:00
Ruben Fiszel
4e477d1f58 fix: update bun t.1.43->1.2.3 2025-02-22 09:23:33 +01:00
Ruben Fiszel
2e4ec7842a chore(main): release 1.467.1 (#5355)
* chore(main): release 1.467.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-22 02:12:27 +01:00
Ruben Fiszel
9ea6776ec1 initialize an uv venv globally but skip it for python executor 2025-02-22 01:53:14 +01:00
Ruben Fiszel
21ca694299 fix python venv 2025-02-22 01:44:45 +01:00
Ruben Fiszel
0aa6a39cad fix: app markdown is selectable in preview mode 2025-02-22 01:15:51 +01:00
Ruben Fiszel
e92a46b088 fix: init_script do not need to use nsjail even in nsjail mode 2025-02-22 01:04:33 +01:00
Ruben Fiszel
85993ccac2 fix: add uv bin path to PATH 2025-02-22 00:50:06 +01:00
Ruben Fiszel
8adedc4964 chore(main): release 1.467.0 (#5344)
* chore(main): release 1.467.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-21 21:29:50 +01:00
Ruben Fiszel
e71882d0a0 add zlib to import parser exception 2025-02-21 21:26:14 +01:00
Ruben Fiszel
ab1c15d92f fix: fix app component header buttons 2025-02-21 21:22:12 +01:00
David Abutbul
d9844fd7f7 feat: enable rust AI gen/fix/edit (#5349)
* init prompts for rust

* generated with yaml2json.py
2025-02-21 21:00:15 +01:00
HugoCasa
a54d8236a8 change workspace id super nit (#5354) 2025-02-21 20:02:13 +01:00
Ruben Fiszel
19a0cde133 job check one last time for completed job before returning 404 2025-02-21 19:57:49 +01:00
HugoCasa
521b6ba92c fix(frontend): improve rename workspace id UX (#5353) 2025-02-21 19:46:58 +01:00
HugoCasa
8a7730efa0 fix(frontend): missing config for Custom AI (#5351) 2025-02-21 18:31:11 +01:00
HugoCasa
7d73decd8d fix(frontend): invalid username for superadmin in some workspaces (#5350) 2025-02-21 18:30:55 +01:00
Ruben Fiszel
7e5469bddf nit 2025-02-21 18:30:37 +01:00
Ruben Fiszel
911fcf2012 improve error message to run executable 2025-02-21 18:09:25 +01:00
Ruben Fiszel
3ac912fa30 fix: handle better forced value propagation in apps 2025-02-21 17:37:25 +01:00
Ruben Fiszel
6d11bb4a00 make cli success page configurable 2025-02-21 17:13:27 +01:00
Ruben Fiszel
6b31a6dee5 fix ansible for nsjail 2025-02-21 17:06:15 +01:00
HugoCasa
19d33bdc7c feat: provision from SSO preferred_username (#5347)
* feat: provision from SSO preferred_username

* update ee ref
2025-02-21 16:20:21 +01:00
Ruben Fiszel
3188bee46e fix: disable toggle is more consistently applied on arg inputs 2025-02-21 14:07:44 +01:00
Ruben Fiszel
03903d06bf nit ansible 2025-02-21 11:22:58 +01:00
Ruben Fiszel
22ff20b6ab nit ansible 2025-02-21 10:12:46 +01:00
Ruben Fiszel
420e65c71c nit ansible galaxy 2025-02-21 10:03:51 +01:00
Ruben Fiszel
90ceb6e4fd uv tool install ansible 2025-02-21 09:50:57 +01:00
Ruben Fiszel
5ad473e12e install ansible with uv pip 2025-02-21 09:44:40 +01:00
Ruben Fiszel
aace016c0c nits install 2025-02-21 09:26:25 +01:00
Ruben Fiszel
676b78b15d fix(image): use debian image instead of python image as base 2025-02-21 09:20:57 +01:00
Ruben Fiszel
312b852c6c do not install pip at all 2025-02-21 08:49:48 +01:00
Ruben Fiszel
f05878271b fix: do not pin python patch version in docker preinstalled python 2025-02-21 08:47:06 +01:00
Ruben Fiszel
c6601da3d8 fix: initialize s3 file input if value already present 2025-02-20 22:05:57 +01:00
Ruben Fiszel
3430f9c439 fix: fix schedule run now args 2025-02-20 19:45:05 +01:00
Ruben Fiszel
c90fe387e8 fix: schedules do not accept 5 units cron syntax on update/create anymore 2025-02-20 17:59:32 +01:00
wendrul
5de1c3ca22 Remove unused import (#5343) 2025-02-20 16:25:24 +01:00
Ruben Fiszel
215dde2813 chore(main): release 1.466.3 (#5341)
* chore(main): release 1.466.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-20 14:34:20 +01:00
wendrul
9ba66eacd2 fix: remove db streaming to avoid backpressure on db (#5342) 2025-02-20 14:27:28 +01:00
HugoCasa
03f88349c8 fix(frontend): add warning when integer number if too big for frontend (#5340) 2025-02-20 14:19:27 +01:00
pyranota
5740679627 fix windows build (#5336) 2025-02-20 09:16:43 +01:00
Ruben Fiszel
05150a0118 chore(main): release 1.466.2 (#5335)
* chore(main): release 1.466.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-20 03:13:13 +01:00
Ruben Fiszel
affb0b4c72 fix: add proxy envs (http_proxy) to uv install 2025-02-20 03:10:09 +01:00
Ruben Fiszel
3e03f86e7d chore(main): release 1.466.1 (#5334)
* chore(main): release 1.466.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-20 03:02:39 +01:00
Ruben Fiszel
39c0dd3736 fix(python): PYTHON_PATH overrides python from uv 2025-02-20 02:54:51 +01:00
Ruben Fiszel
d5b3a04b0a fix(cli): improve flow cli dependency error clarity 2025-02-20 02:48:17 +01:00
Ruben Fiszel
2c67e84abe fix(cli): improve dependency job error message (logs in result) 2025-02-20 01:52:18 +01:00
Ruben Fiszel
dcc0d35e97 fix(cli): improve cli dependency error clarity 2025-02-20 01:51:47 +01:00
pyranota
5a3ca3c8f2 fix windows build (#5333) 2025-02-20 00:26:09 +01:00
Ruben Fiszel
00d2d08e75 chore(main): release 1.466.0 (#5326)
* chore(main): release 1.466.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-19 22:25:32 +01:00
Ruben Fiszel
74c0a10c3a fix: improve app db explorer handling of always identity columns 2025-02-19 21:49:25 +01:00
Alexander Petric
ee4a9c6592 teams cleanup cleanup (#5330)
* sqlx

* repo ref

* adding teams channel to criticalerrorchannel in non-ee
2025-02-19 19:01:18 +01:00
pyranota
4ad654fcf0 feat: remove pip fallback option for python and ansible (#5186) 2025-02-19 17:33:11 +01:00
HugoCasa
35d5293fba feat: add support for gemini (#5235)
* feat: add support for gemini

* nit

* fix
2025-02-19 15:03:35 +01:00
Ruben Fiszel
defa66eb06 add otel to rh images 2025-02-19 08:11:06 +01:00
Ruben Fiszel
44a6a62fbe fix(apps): font-size of title text not screen dependent 2025-02-19 01:31:03 +01:00
Ruben Fiszel
e19fc6723e chore(main): release 1.465.0 (#5324)
* chore(main): release 1.465.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-18 23:54:38 +01:00
dieriba
58a67a3ac0 feat: SQS triggers (#5182)
* feat: first commit

* fix: npm check

* fix: openapi file

* feat: update openapi and migration

* feat: basic implementation done

* fix: fix: no used function when no feature

* feat: capture done

* Update capture.rs

* nits: change sqs trigger

* fix: make migration great again

* feat: add message attributes

* feat: nits: fix error messages, remove console.log and add try catch

* update sqs icon and ee feature for sqs_trigger

* update: change sqs name casing and added test connection button

* nits: update Icon and add create from template button

* fix: ci build and error compilation

* update migration type sqs

* update link on create from template button for sqs, add archive in workspace export and update sqlx

* fix: ci

* Update SqsTriggerEditorInner.svelte

* add link to docs, use generic function for resource and fix import error

* chore: update .github ci

* nits: remove empty

* update to match ee repo changement

* Update backend/windmill-api/src/resources.rs

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* add sqs handling for the cli and refacoring sqsEditorInner

* Update cli/sync.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix: add break to switch statement for sqs case

* fix: display aws_resource_path when retrieve or create a new trigger

* rework sqs ui, fix postgres optional port

* fix: ci

* update ui for trigger

* update repo ref and specific

* feat: add ready endpoints for workers to enterprise

* update ref

* Update frontend/src/lib/script_helpers.ts

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: HugoCasa <hugo@casademont.ch>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-02-18 23:49:45 +01:00
Ruben Fiszel
0e72991476 fix: fix rendering of app components without component inputs 2025-02-18 23:34:17 +01:00
Ruben Fiszel
8559c4e23e chore(main): release 1.464.0 (#5322)
* chore(main): release 1.464.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-18 21:57:34 +01:00
Ruben Fiszel
1ef482e8ae feat: add ready endpoints for workers to enterprise 2025-02-18 21:49:35 +01:00
Ruben Fiszel
52ad48a910 back to pipe in bash for efficiency purposes 2025-02-18 20:08:25 +01:00
434 changed files with 15392 additions and 7940 deletions

View File

@@ -7,7 +7,6 @@ services:
# image: mcr.microsoft.com/vscode/devcontainers/rust:bullseye
environment:
- DENO_PATH=/usr/local/cargo/bin/deno
- PYTHON_PATH=/usr/bin/python3
- NSJAIL_PATH=/bin/nsjail
volumes:
- .:/workspace:cached

View File

@@ -40,7 +40,7 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER
RUN /usr/local/bin/python3 -m pip install pip-tools
COPY --from=oven/bun:1.1.31 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.2.3 /usr/local/bin/bun /usr/bin/bun
ARG TARGETPLATFORM

View File

@@ -16,7 +16,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.83.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
@@ -40,7 +40,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.83.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
@@ -77,7 +77,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.83.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
@@ -117,7 +117,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.83.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend

View File

@@ -42,9 +42,6 @@ jobs:
- uses: actions/setup-go@v2
with:
go-version: 1.21.5
- uses: actions/setup-python@v2
with:
python-version: 3.11
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.43
@@ -54,7 +51,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.83.0
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
@@ -64,7 +61,7 @@ jobs:
deno --version && bun -v && go version && python3 --version &&
SQLX_OFFLINE=true
DATABASE_URL=postgres://postgres:changeme@localhost:5432/windmill
DISABLE_EMBEDDING=true RUST_LOG=info PYTHON_PATH=$(which python)
DISABLE_EMBEDDING=true RUST_LOG=info
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go)
UV_PATH=$(which uv) cargo test --features
enterprise,deno_core,license,python,rust,scoped_cache --all --

View File

@@ -64,7 +64,7 @@ jobs:
platforms: linux/amd64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
@@ -81,7 +81,7 @@ jobs:
platforms: linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}

View File

@@ -30,6 +30,12 @@ jobs:
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
override: true
- name: Substitute EE code
shell: bash
run: |
@@ -45,7 +51,7 @@ jobs:
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
mkdir frontend/build && cd backend
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
- name: Rename binary with corresponding architecture
run: |

View File

@@ -158,7 +158,7 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,otel,dind,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
${{ steps.meta-ee-public.outputs.tags }}
@@ -452,49 +452,6 @@ jobs:
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
build_ee_reports_privately:
needs: [build_ee_nsjail]
runs-on: ubicloud
if: github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch')
steps:
- uses: actions/checkout@v4
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@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta-ee-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-reports
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,enable=true,priority=100,prefix=,suffix=,format=short
- name: Build and push publicly ee reports
uses: depot/build-push-action@v1
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileReports"
tags: |
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
publish_ecr_s3:
needs: [build_ee_nsjail]

View File

@@ -32,6 +32,12 @@ jobs:
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
override: true
- name: Substitute EE code
shell: bash
run: |
@@ -47,7 +53,7 @@ jobs:
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
mkdir frontend/build && cd backend
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,php,mysql,mssql,bigquery,oracledb,postgres_trigger,websocket,python,smtp,csharp,static_frontend,rust
- name: Rename binary with corresponding architecture
run: |

View File

@@ -1,5 +1,209 @@
# Changelog
## [1.473.0](https://github.com/windmill-labs/windmill/compare/v1.472.1...v1.473.0) (2025-03-03)
### Features
* app s3 input anonymous delete ([#5401](https://github.com/windmill-labs/windmill/issues/5401)) ([46c7845](https://github.com/windmill-labs/windmill/commit/46c784574add176cb75d3627c9d3f55b6fb945f8))
* track workspace runnables used in flows ([#5369](https://github.com/windmill-labs/windmill/issues/5369)) ([7bf9e25](https://github.com/windmill-labs/windmill/commit/7bf9e25ede82486115eae71865202f85aa931a8d))
### Bug Fixes
* improve db loads by adding index on audit ([e1ff001](https://github.com/windmill-labs/windmill/commit/e1ff00117ca5b66dd0b9365e63b9ff7dc277bc2c))
* migrations do not refer to public schema anymore ([#5400](https://github.com/windmill-labs/windmill/issues/5400)) ([3063001](https://github.com/windmill-labs/windmill/commit/3063001491b49a4b6d0cd5985818b32aa4d3f16f))
* remove typings_extensions from python sdk ([04ffbf8](https://github.com/windmill-labs/windmill/commit/04ffbf8c266a06c3efcebcbbaee767f0ab0771e2))
## [1.472.1](https://github.com/windmill-labs/windmill/compare/v1.472.0...v1.472.1) (2025-02-26)
### Bug Fixes
* disable bundling using env var ([#5396](https://github.com/windmill-labs/windmill/issues/5396)) ([cb559d6](https://github.com/windmill-labs/windmill/commit/cb559d6083553c400e18e6077002c4891289a8a2))
## [1.472.0](https://github.com/windmill-labs/windmill/compare/v1.471.1...v1.472.0) (2025-02-26)
### Bug Fixes
* downgrade v8 to fix some rare panics ([5569e4d](https://github.com/windmill-labs/windmill/commit/5569e4d4953a01f2ad03ea8b71e695e833964bea))
* **frontend:** markdown shows single backtick in single line code block ([#5391](https://github.com/windmill-labs/windmill/issues/5391)) ([7f290bb](https://github.com/windmill-labs/windmill/commit/7f290bbf6a33e2811dbe2bd8ee905c0fa8e8db3b))
* migrate toggle to melt (4/4) ([#5329](https://github.com/windmill-labs/windmill/issues/5329)) ([69fc8a9](https://github.com/windmill-labs/windmill/commit/69fc8a98ae78bc01dc3d97f9732ee28864b323dd))
## [1.471.1](https://github.com/windmill-labs/windmill/compare/v1.471.0...v1.471.1) (2025-02-26)
### Bug Fixes
* update to rust 1.86.0 ([3ada264](https://github.com/windmill-labs/windmill/commit/3ada264c4ad49f666c3a053eb48c7df294bf085b))
## [1.471.0](https://github.com/windmill-labs/windmill/compare/v1.470.1...v1.471.0) (2025-02-26)
### Features
* add support for claude sonnet 3.7 thinking ([#5387](https://github.com/windmill-labs/windmill/issues/5387)) ([487d84b](https://github.com/windmill-labs/windmill/commit/487d84bd7fdc39a2401df4108fca6183189cf38a))
### Bug Fixes
* **frontend:** improve pagination handling and filter refreshes ([#5378](https://github.com/windmill-labs/windmill/issues/5378)) ([a85ebfb](https://github.com/windmill-labs/windmill/commit/a85ebfbbf48590812c0931ad93179c322f819849))
## [1.470.1](https://github.com/windmill-labs/windmill/compare/v1.470.0...v1.470.1) (2025-02-26)
### Bug Fixes
* multiple app initializations fixes ([630e54f](https://github.com/windmill-labs/windmill/commit/630e54f65c950ec0073b3cdac9974cb666c1ab3f))
## [1.470.0](https://github.com/windmill-labs/windmill/compare/v1.469.0...v1.470.0) (2025-02-26)
### Features
* **frontend:** set default app refesh interval ([#5380](https://github.com/windmill-labs/windmill/issues/5380)) ([478d3fb](https://github.com/windmill-labs/windmill/commit/478d3fbf4a7e52d19fcb5cf8d601b2eeb3487716))
### Bug Fixes
* multiple app initializations fixes ([24b6003](https://github.com/windmill-labs/windmill/commit/24b600378025632aecb2ca898b63d6032e08eb2e))
## [1.469.0](https://github.com/windmill-labs/windmill/compare/v1.468.0...v1.469.0) (2025-02-25)
### Features
* limit the number of times a job can be restarted (3) after loss of pings ([c8a9596](https://github.com/windmill-labs/windmill/commit/c8a959691c37350def37fe3eb9f24c6f7789960d))
* python-client now support mocked api via `WM_MOCKED_API_FILE` env ([#5372](https://github.com/windmill-labs/windmill/issues/5372)) ([50607c7](https://github.com/windmill-labs/windmill/commit/50607c7625e4a48fb397cff167b41bb6602716c0))
### Bug Fixes
* improve flow editor for vscode extension ([44b26d2](https://github.com/windmill-labs/windmill/commit/44b26d2ccec0c9dd65d1f53b057d031f841d7dba))
* improve infinite grid behavior ([56d1da7](https://github.com/windmill-labs/windmill/commit/56d1da78fd3424ae5b4abbb009c7437ea98765ef))
## [1.468.0](https://github.com/windmill-labs/windmill/compare/v1.467.1...v1.468.0) (2025-02-24)
### Features
* add audit logs scope filter in admins workspace ([#5352](https://github.com/windmill-labs/windmill/issues/5352)) ([b3e00b7](https://github.com/windmill-labs/windmill/commit/b3e00b7fdc3ad4c689fc30216accbed05822794c))
* add support for | None and Optional in python ([#5361](https://github.com/windmill-labs/windmill/issues/5361)) ([9736355](https://github.com/windmill-labs/windmill/commit/9736355d5f82615100212698c5537997e5a0de39))
* make flow lock deployment error visible in UI ([b8e6d0d](https://github.com/windmill-labs/windmill/commit/b8e6d0da79ca57b115e7cb0ccff9f5623b23f3f3))
### Bug Fixes
* add LOCALAPPDATA env variable to python execution on windows ([8806870](https://github.com/windmill-labs/windmill/commit/8806870b1bf67c2f77beaf04d986cf172c7b4bf4))
* fix confirmation modal check on deploy ([3028325](https://github.com/windmill-labs/windmill/commit/3028325615e2f7e5ee3d1b6278580121880db14f))
* **frontend:** make html app component content selectable ([#5359](https://github.com/windmill-labs/windmill/issues/5359)) ([f1c5b77](https://github.com/windmill-labs/windmill/commit/f1c5b77d7af8433905937d274b97c2d5cd6c1316))
* handle better forced value propagation in apps ([7c842c8](https://github.com/windmill-labs/windmill/commit/7c842c88bf5225b6bc39857109b1b1ba5f99d708))
* handle better optional chaining operator ([d45c1f6](https://github.com/windmill-labs/windmill/commit/d45c1f69d48a5ad93f4399ce0150bbff6fd4fa6b))
* improve app markdown rendering ([96597d3](https://github.com/windmill-labs/windmill/commit/96597d3d6b3d31298e5582a55e11e1d48edbf175))
* improve cancel/back behavior on editors ([0565981](https://github.com/windmill-labs/windmill/commit/05659816e722effcba27e71f855e819c606f8756))
* improve custom component rendering ([4ee4ff7](https://github.com/windmill-labs/windmill/commit/4ee4ff78d389d61c63952c84dee967113c783c45))
* improve webhook settings cache invalidation ([0456272](https://github.com/windmill-labs/windmill/commit/0456272e3f36996c5f223fc332b150c7a64c2f05))
* update bun t.1.43-&gt;1.2.3 ([4e477d1](https://github.com/windmill-labs/windmill/commit/4e477d1f589343980d7bd2953909ff6a6be30739))
* update deno 2.1.2-&gt;2.2.1 ([b102ff4](https://github.com/windmill-labs/windmill/commit/b102ff4a4643e2f06d44d493f2f776b44ae721cc))
## [1.467.1](https://github.com/windmill-labs/windmill/compare/v1.467.0...v1.467.1) (2025-02-22)
### Bug Fixes
* add uv bin path to PATH ([85993cc](https://github.com/windmill-labs/windmill/commit/85993ccac2abc2295e0f1b21544a6674fcf43411))
* app markdown is selectable in preview mode ([0aa6a39](https://github.com/windmill-labs/windmill/commit/0aa6a39cad16bff74adf3326d47ba0ba9851ccf6))
* init_script do not need to use nsjail even in nsjail mode ([e92a46b](https://github.com/windmill-labs/windmill/commit/e92a46b088088148d13a8e625a828657bcf44fe3))
## [1.467.0](https://github.com/windmill-labs/windmill/compare/v1.466.3...v1.467.0) (2025-02-21)
### Features
* enable rust AI gen/fix/edit ([#5349](https://github.com/windmill-labs/windmill/issues/5349)) ([d9844fd](https://github.com/windmill-labs/windmill/commit/d9844fd7f7cf89a0914176944d4af0b485ed3f3c))
* provision from SSO preferred_username ([#5347](https://github.com/windmill-labs/windmill/issues/5347)) ([19d33bd](https://github.com/windmill-labs/windmill/commit/19d33bdc7c4633f0c338c77de1d316f733e4304a))
### Bug Fixes
* disable toggle is more consistently applied on arg inputs ([3188bee](https://github.com/windmill-labs/windmill/commit/3188bee46e3dc46a699096bd3c2668df0cbdb9a1))
* do not pin python patch version in docker preinstalled python ([f058782](https://github.com/windmill-labs/windmill/commit/f05878271becb28f83678c5b0ae498d0192b2458))
* fix app component header buttons ([ab1c15d](https://github.com/windmill-labs/windmill/commit/ab1c15d92f3f86f4bd8d782fa6a806a59f30fdf1))
* fix schedule run now args ([3430f9c](https://github.com/windmill-labs/windmill/commit/3430f9c4390b6c630086394ddfaf1a1b2030c78f))
* **frontend:** improve rename workspace id UX ([#5353](https://github.com/windmill-labs/windmill/issues/5353)) ([521b6ba](https://github.com/windmill-labs/windmill/commit/521b6ba92c86a55b9977463ae05ecd4fca400ce4))
* **frontend:** invalid username for superadmin in some workspaces ([#5350](https://github.com/windmill-labs/windmill/issues/5350)) ([7d73dec](https://github.com/windmill-labs/windmill/commit/7d73decd8dc7039ef84915994074c07dc51280c9))
* **frontend:** missing config for Custom AI ([#5351](https://github.com/windmill-labs/windmill/issues/5351)) ([8a7730e](https://github.com/windmill-labs/windmill/commit/8a7730efa06283e72292d894584b279c908a7604))
* handle better forced value propagation in apps ([3ac912f](https://github.com/windmill-labs/windmill/commit/3ac912fa308fbbf6cf41562cfdbe8eea7c1cc372))
* **image:** use debian image instead of python image as base ([676b78b](https://github.com/windmill-labs/windmill/commit/676b78b15db8e1c749107fa41c4c98ab3a37154e))
* initialize s3 file input if value already present ([c6601da](https://github.com/windmill-labs/windmill/commit/c6601da3d8557af9d32b0202bf50c40b89d481a9))
* schedules do not accept 5 units cron syntax on update/create anymore ([c90fe38](https://github.com/windmill-labs/windmill/commit/c90fe387e882f7767c3b3621e5e230fc8acd80b0))
## [1.466.3](https://github.com/windmill-labs/windmill/compare/v1.466.2...v1.466.3) (2025-02-20)
### Bug Fixes
* **frontend:** add warning when integer number if too big for frontend ([#5340](https://github.com/windmill-labs/windmill/issues/5340)) ([03f8834](https://github.com/windmill-labs/windmill/commit/03f88349c8730bfbb4613105c35482b4f3fadd64))
* remove db streaming to avoid backpressure on db ([#5342](https://github.com/windmill-labs/windmill/issues/5342)) ([9ba66ea](https://github.com/windmill-labs/windmill/commit/9ba66eacd28175607900a7d2294584662b4c26a2))
## [1.466.2](https://github.com/windmill-labs/windmill/compare/v1.466.1...v1.466.2) (2025-02-20)
### Bug Fixes
* add proxy envs (http_proxy) to uv install ([affb0b4](https://github.com/windmill-labs/windmill/commit/affb0b4c720551f7f1c7fa5315e3b39e5580b732))
## [1.466.1](https://github.com/windmill-labs/windmill/compare/v1.466.0...v1.466.1) (2025-02-20)
### Bug Fixes
* **cli:** improve cli dependency error clarity ([dcc0d35](https://github.com/windmill-labs/windmill/commit/dcc0d35e971ab3df6a0122dc881b968e8221f40f))
* **cli:** improve dependency job error message (logs in result) ([2c67e84](https://github.com/windmill-labs/windmill/commit/2c67e84abe98a3c43972cf5555536104119c6527))
* **cli:** improve flow cli dependency error clarity ([d5b3a04](https://github.com/windmill-labs/windmill/commit/d5b3a04b0ab5f003c4c512cc9ba74eb620a3afc1))
* **python:** PYTHON_PATH overrides python from uv ([39c0dd3](https://github.com/windmill-labs/windmill/commit/39c0dd3736da0722c7e18d84183c0e9b06cf2839))
## [1.466.0](https://github.com/windmill-labs/windmill/compare/v1.465.0...v1.466.0) (2025-02-19)
### Features
* add support for gemini ([#5235](https://github.com/windmill-labs/windmill/issues/5235)) ([35d5293](https://github.com/windmill-labs/windmill/commit/35d5293fba47d368e503e9781719e6e9ccc96713))
* remove `pip` fallback option for python and ansible ([#5186](https://github.com/windmill-labs/windmill/issues/5186)) ([4ad654f](https://github.com/windmill-labs/windmill/commit/4ad654fcf0c603aefc5a9b5c41da1ffa24b99d2d))
### Bug Fixes
* **apps:** font-size of title text not screen dependent ([44a6a62](https://github.com/windmill-labs/windmill/commit/44a6a62fbe3a9cae79e2d7ab7efd119f559aa374))
* improve app db explorer handling of always identity columns ([74c0a10](https://github.com/windmill-labs/windmill/commit/74c0a10c3a8a4848341456635f36c0c2061b7943))
## [1.465.0](https://github.com/windmill-labs/windmill/compare/v1.464.0...v1.465.0) (2025-02-18)
### Features
* SQS triggers ([#5182](https://github.com/windmill-labs/windmill/issues/5182)) ([58a67a3](https://github.com/windmill-labs/windmill/commit/58a67a3ac0c57b9504a90a6e454f738cf0810e21))
### Bug Fixes
* fix rendering of app components without component inputs ([0e72991](https://github.com/windmill-labs/windmill/commit/0e72991476ba932a526e1b4cf42bad157be2cfdb))
## [1.464.0](https://github.com/windmill-labs/windmill/compare/v1.463.6...v1.464.0) (2025-02-18)
### Features
* add ready endpoints for workers to enterprise ([1ef482e](https://github.com/windmill-labs/windmill/commit/1ef482e8aee9433c518ce3cbc5bc38174e27c34f))
### Bug Fixes
* **bash:** allow process substitution on nsjail ([d4f61f1](https://github.com/windmill-labs/windmill/commit/d4f61f13fd6a9c2e5707738fba960b7fd926230c))
* **bash:** improve bash last line as result reliability using bash process substitution ([#5321](https://github.com/windmill-labs/windmill/issues/5321)) ([138cedf](https://github.com/windmill-labs/windmill/commit/138cedf1da91290f97c19513daf0c1981488a94a))
## [1.463.6](https://github.com/windmill-labs/windmill/compare/v1.463.5...v1.463.6) (2025-02-18)

View File

@@ -1,6 +1,5 @@
ARG DEBIAN_IMAGE=debian:bookworm-slim
ARG RUST_IMAGE=rust:1.83-slim-bookworm
ARG PYTHON_IMAGE=python:3.11.10-slim-bookworm
ARG RUST_IMAGE=rust:1.85-slim-bookworm
FROM ${RUST_IMAGE} AS rust_base
@@ -81,7 +80,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release --features "$features"
FROM ${PYTHON_IMAGE}
FROM ${DEBIAN_IMAGE}
ARG TARGETPLATFORM
ARG POWERSHELL_VERSION=7.3.5
@@ -102,11 +101,13 @@ ARG WITH_GIT=true
ARG LATEST_STABLE_PY=3.11.10
ENV UV_PYTHON_INSTALL_DIR=/tmp/windmill/cache/py_runtime
ENV UV_PYTHON_PREFERENCE=only-managed
ENV UV_TOOL_BIN_DIR=/usr/local/bin
ENV PATH /usr/local/bin:/root/.local/bin:$PATH
RUN pip install --upgrade pip==24.2
RUN apt-get update \
&& apt-get install -y ca-certificates wget curl jq unzip build-essential unixodbc xmlsec1 software-properties-common \
&& apt-get install -y --no-install-recommends netbase tzdata ca-certificates wget curl jq unzip build-essential unixodbc xmlsec1 software-properties-common \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@@ -167,12 +168,15 @@ ENV PATH="${PATH}:/usr/local/go/bin"
ENV GO_PATH=/usr/local/go/bin/go
# Install UV
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.5.15/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.6.2/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
# Preinstall python runtimes
RUN uv python install 3.11.10
RUN uv python install 3.11
RUN uv python install $LATEST_STABLE_PY
RUN uv venv
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get -y update && apt-get install -y curl procps nodejs awscli && apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@@ -182,14 +186,12 @@ RUN mkdir -p /tmp/gobuildwarm && cd /tmp/gobuildwarm && go mod init gobuildwarm
ENV TZ=Etc/UTC
RUN /usr/local/bin/python3 -m pip install pip-tools
COPY --from=builder /frontend/build /static_frontend
COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
COPY --from=denoland/deno:2.1.2 --chmod=755 /usr/bin/deno /usr/bin/deno
COPY --from=denoland/deno:2.2.1 --chmod=755 /usr/bin/deno /usr/bin/deno
COPY --from=oven/bun:1.1.43 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.2.3 /usr/local/bin/bun /usr/bin/bun
COPY --from=php:8.3.7-cli /usr/local/bin/php /usr/bin/php
COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer

View File

@@ -330,7 +330,7 @@ you to have it being synced automatically everyday.
| SLACK_SIGNING_SECRET | None | The signing secret of your Slack app. See [Slack documentation](https://api.slack.com/authentication/verifying-requests-from-slack) | Server |
| COOKIE_DOMAIN | None | The domain of the cookie. If not set, the cookie will be set by the browser based on the full origin | Server |
| DENO_PATH | /usr/bin/deno | The path to the deno binary. | Worker |
| PYTHON_PATH | /usr/local/bin/python3 | The path to the python binary. | Worker |
| PYTHON_PATH | | The path to the python binary if wanting to not have it managed by uv. | Worker |
| GO_PATH | /usr/bin/go | The path to the go binary. | Worker |
| GOPRIVATE | | The GOPRIVATE env variable to use private go modules | Worker |
| GOPROXY | | The GOPROXY env variable to use | Worker |

View File

@@ -19,7 +19,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -0,0 +1,26 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n sqs_trigger \n SET \n enabled = $1, \n email = $2, \n edited_by = $3, \n edited_at = now(), \n server_id = NULL, \n error = NULL\n WHERE \n path = $4 AND \n workspace_id = $5 \n RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Bool",
"Varchar",
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "1625a84fbcf8c5f77eb0519f60d9418f85d4d3d599f4177403fad5ad99380715"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO job_logs (job_id, logs)\n VALUES ($1, $2)\n ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\n' || EXCLUDED.logs\n WHERE job_logs.job_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": []
},
"hash": "1ab0d1ba1fbfad31ffb28a01a6c9640d0ac142aabee8d288a4f9c56ad9dbeac4"
}

View File

@@ -0,0 +1,50 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n path,\n is_flow,\n workspace_id,\n owner,\n email,\n trigger_config as \"trigger_config!: _\"\n FROM\n capture_config\n WHERE\n trigger_kind = 'sqs' AND\n last_client_ping > NOW() - INTERVAL '10 seconds' AND\n trigger_config IS NOT NULL AND\n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "trigger_config!: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false,
false,
false,
true
]
},
"hash": "1b33393fbbc7e681b4d355f6096d982b52b48c8c3da392b14963a1ec86811546"
}

View File

@@ -0,0 +1,26 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n capture_config \n SET \n last_server_ping = now(), \n error = $1 \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'sqs' AND \n server_id = $5 AND \n last_client_ping > NOW() - INTERVAL '10 seconds' \n RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool",
"Text"
]
},
"nullable": [
null
]
},
"hash": "1cad25c24d0f80d58a50d4da923f8b0672797299545ee0754b6ad74ece92c77e"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE \n capture_config \n SET \n last_server_ping = NULL \n WHERE \n workspace_id = $1 AND \n path = $2 AND \n is_flow = $3 AND \n trigger_kind = 'sqs' AND \n server_id IS NULL\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "20e01ecb5d4aa4c532a8f906365c776994ae2c990bb7bb307c52296b9543fbb8"
}

View File

@@ -0,0 +1,25 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n sqs_trigger\n SET \n last_server_ping = now(),\n error = $1\n WHERE\n workspace_id = $2\n AND path = $3\n AND server_id = $4 \n AND enabled IS TRUE\n RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "22dcd953d900fb0ddbe2099ccee27bcf833f56475bbc1aa3c8f6d79f146f41bf"
}

View File

@@ -0,0 +1,106 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM sqs_trigger\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "queue_url",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "aws_resource_path",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "message_attributes",
"type_info": "TextArray"
},
{
"ordinal": 4,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 11,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 12,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 14,
"name": "enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
true,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
false
]
},
"hash": "2b6c13191484b0c664f35e2c811082b00c44fd4a7e98a11b714133674a7b6da7"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow SET path = $1, summary = $2, description = $3,dependency_job = NULL, draft_only = NULL, tag = $4, dedicated_worker = $5, visible_to_runner_only = $6, on_behalf_of_email = $7, value = $8, schema = $9::text::json, edited_by = $10, edited_at = now()\n WHERE path = $11 AND workspace_id = $12",
"query": "UPDATE flow SET path = $1, summary = $2, description = $3,dependency_job = NULL, lock_error_logs = '', draft_only = NULL, tag = $4, dedicated_worker = $5, visible_to_runner_only = $6, on_behalf_of_email = $7, value = $8, schema = $9::text::json, edited_by = $10, edited_at = now()\n WHERE path = $11 AND workspace_id = $12",
"describe": {
"columns": [],
"parameters": {
@@ -21,5 +21,5 @@
},
"nullable": []
},
"hash": "ba8bde5018fdf7b12f85cd3a6557c4accfc78bf160c1277f35d9d8ddcd056963"
"hash": "2b9607ed838c8c62eb0f2856420389f7be648f52edbb875ff52c96219ed3ba84"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow_workspace_runnables SET workspace_id = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "2bb2cf6accb18d3e37a63388cca52a6591e7593b1a7c3d7a6848587679a48187"
}

View File

@@ -0,0 +1,107 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n aws_resource_path,\n message_attributes,\n queue_url,\n workspace_id,\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n sqs_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "aws_resource_path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "message_attributes",
"type_info": "TextArray"
},
{
"ordinal": 2,
"name": "queue_url",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 12,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 14,
"name": "enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
false
]
},
"hash": "2ef82fad8a6ccdc66228cfbce5393de351653ab9ac171fa0eea447c905440867"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow_workspace_runnables (flow_path, runnable_path, runnable_is_flow, workspace_id) VALUES ($1, $2, TRUE, $3) ON CONFLICT DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "35795d27c4ca69d2f145b4dba08a6ed16c25aea4584103c1b9a3651eb31bfe53"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n sqs_trigger \n SET \n enabled = FALSE, \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "3f67e7cf8d9f021a075f1c88703287a9f42e252a1246a584249a224afdbbbf8a"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "CREATE INDEX CONCURRENTLY ix_audit_timestamps ON audit (timestamp DESC)",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "47baef9304533898ae52328d946edc053bd3332f886a8bc6cb173cdea7e8aa16"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO metrics (id, value) \n VALUES ('no_uv_usage_ansible', $1)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb"
]
},
"nullable": []
},
"hash": "4a804ee30bfe86c4e2c15a9f6511be5adf0dd22cb942fac64b439fb4e20df447"
}

View File

@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n sqs_trigger \n SET \n server_id = $1, \n last_server_ping = now(),\n error = 'Connecting...'\n WHERE \n enabled IS TRUE \n AND workspace_id = $2 \n AND path = $3 \n AND (last_server_ping IS NULL \n OR last_server_ping < now() - INTERVAL '15 seconds'\n ) \n RETURNING true\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "5bd8ae8d694ac9f6afef762276141d95ba195f5543120e76e68f6e6715b65a71"
}

View File

@@ -27,7 +27,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}
@@ -60,7 +61,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -19,7 +19,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "WITH zombie_jobs AS (\n UPDATE v2_job_queue q SET running = false, started_at = null\n FROM v2_job j, v2_job_runtime r\n WHERE j.id = q.id AND j.id = r.id\n AND ping < now() - ($1 || ' seconds')::interval\n AND running = true\n AND kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow')\n AND same_worker = false\n RETURNING q.id, q.workspace_id, ping\n ),\n update_concurrency AS (\n UPDATE concurrency_counter cc\n SET job_uuids = job_uuids - zj.id::text\n FROM zombie_jobs zj\n INNER JOIN concurrency_key ck ON ck.job_id = zj.id\n WHERE cc.concurrency_id = ck.key\n )\n SELECT id, workspace_id, ping FROM zombie_jobs",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "ping",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
true
]
},
"hash": "653574b381a31548d82c1f6f3f44ec826597c42310ab78f9aacd7d9448206c6a"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET teams_command_script = NULL,\n teams_team_id = NULL,\n teams_team_name = NULL\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "65c339164e7669360d231d70105849e72bdc197c17c0fc51777c1dc9267e2daf"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO job_logs (job_id, logs)\n VALUES ($1, 'Restarted job after not receiving job''s ping for too long the ' || now() || '\n\n')\n ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\n' || EXCLUDED.logs\n WHERE job_logs.job_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": []
},
"hash": "67afe352fc26dda9107c90e50e954642d877178ce2c0e73b72c3824135ef86f4"
}

View File

@@ -0,0 +1,25 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n capture_config \n SET \n server_id = $1,\n last_server_ping = now(), \n error = 'Connecting...' \n WHERE \n last_client_ping > NOW() - INTERVAL '10 seconds' AND \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'sqs' AND \n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') \n RETURNING true\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text",
"Bool"
]
},
"nullable": [
null
]
},
"hash": "6b776693091191f36eaf9e35fb3cabb01481a19bef5a956dc36cac41acad0e53"
}

View File

@@ -30,7 +30,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -0,0 +1,17 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n capture_config \n SET \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'sqs'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "7e31c47e02492b74cbb5702dfc5ef9f4c8faa986843024a2cd58e212f706aae8"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE global_settings\n SET value = (\n SELECT COALESCE(jsonb_agg(elem), '[]'::jsonb)\n FROM jsonb_array_elements(value) AS elem\n WHERE NOT (elem ? 'teams_channel')\n )\n WHERE name = 'critical_error_channels'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "81b06122c7a12a314d8905ba5c7c14aa7614f2610e79a8c7302eaa63fb74984d"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n \n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\", \n \n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\"\n ",
"query": "\n SELECT \n \n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\", \n \n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\"\n ",
"describe": {
"columns": [
{
@@ -27,6 +27,11 @@
"ordinal": 4,
"name": "postgres_used!",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "sqs_used!",
"type_info": "Bool"
}
],
"parameters": {
@@ -39,8 +44,9 @@
null,
null,
null,
null,
null
]
},
"hash": "24178c21aadc1aed90f31e9362c6505a642c8f04b883c278b07e7ef5956ce121"
"hash": "93d0ee34c7b7c56ab9cae28071f8e5fdaff0e601e2760cc5653d197c51b106bb"
}

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT lock_error_logs FROM flow WHERE path = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "lock_error_logs",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
true
]
},
"hash": "97bf27f210572499b42ce04f19f116cc87ed06c49dcca04360250ddfd89d7ab3"
}

View File

@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "SELECT f.path\n FROM flow_workspace_runnables fwr \n JOIN flow f \n ON fwr.flow_path = f.path AND fwr.workspace_id = f.workspace_id\n WHERE fwr.runnable_path = $1 AND fwr.runnable_is_flow = $2 AND fwr.workspace_id = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Bool",
"Text"
]
},
"nullable": [
false
]
},
"hash": "9aeee333b1dbe58ba819ba3b2713242b54d77b46b5f785ae66b8104f89f43219"
}

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO sqs_trigger (\n aws_resource_path,\n queue_url,\n message_attributes,\n workspace_id, \n path, \n script_path, \n is_flow, \n email, \n enabled, \n edited_by\n ) \n VALUES (\n $1, \n $2, \n $3, \n $4, \n $5, \n $6, \n $7,\n $8,\n $9,\n $10\n )",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"TextArray",
"Varchar",
"Varchar",
"Varchar",
"Bool",
"Varchar",
"Bool",
"Varchar"
]
},
"nullable": []
},
"hash": "9b9bc21023f10a0b4bb45879c7da8e119bffd2982b97fc900358506a0a14bbb8"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n sqs_trigger \n SET\n last_server_ping = NULL \n WHERE \n workspace_id = $1 \n AND path = $2 \n AND server_id IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "a5fbef9db2308920ea26f6154f0f3490f88ced636c9ebdecba2205f964b1d0f1"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM flow_workspace_runnables WHERE flow_path = $1 AND workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "acbea8740b28c26942c50edcf5618cd141e68cf83a7dcae7d3c1b8a7ba94425b"
}

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT EXISTS(\n SELECT \n 1 \n FROM \n sqs_trigger \n WHERE \n path = $1 AND \n workspace_id = $2\n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "b386d320f9fe1d569a16e6626b723b4376a93342702856da2ac70f6bbfc7933e"
}

View File

@@ -0,0 +1,41 @@
{
"db_name": "PostgreSQL",
"query": "WITH to_update AS (\n SELECT q.id, q.workspace_id, r.ping, COALESCE(zjc.counter, 0) as counter\n FROM v2_job_queue q\n JOIN v2_job j ON j.id = q.id\n JOIN v2_job_runtime r ON r.id = j.id\n LEFT JOIN zombie_job_counter zjc ON zjc.job_id = q.id\n WHERE ping < now() - ($1 || ' seconds')::interval\n AND running = true\n AND kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow')\n AND same_worker = false\n AND (zjc.counter IS NULL OR zjc.counter <= $2)\n FOR UPDATE of q SKIP LOCKED\n ),\n zombie_jobs AS (\n UPDATE v2_job_queue q\n SET running = false, started_at = null\n FROM to_update tu\n WHERE q.id = tu.id AND (tu.counter IS NULL OR tu.counter < $2)\n RETURNING q.id, q.workspace_id, ping, tu.counter\n ),\n increment_counter AS (\n INSERT INTO zombie_job_counter (job_id, counter)\n SELECT id, 1 FROM to_update WHERE counter < $2\n ON CONFLICT (job_id) DO UPDATE \n SET counter = zombie_job_counter.counter + 1\n ),\n update_concurrency AS (\n UPDATE concurrency_counter cc\n SET job_uuids = job_uuids - zj.id::text\n FROM zombie_jobs zj\n INNER JOIN concurrency_key ck ON ck.job_id = zj.id\n WHERE cc.concurrency_id = ck.key\n )\n SELECT id AS \"id!\", workspace_id AS \"workspace_id!\", ping, counter + 1 AS counter FROM to_update",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id!",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "workspace_id!",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "ping",
"type_info": "Timestamptz"
},
{
"ordinal": 3,
"name": "counter",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Int4"
]
},
"nullable": [
false,
false,
true,
null
]
},
"hash": "b45dc2baa48df2272dbac6e3537fc59ad8fab54027a9993cb61cdde68df3cbe6"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow_workspace_runnables SET flow_path = REGEXP_REPLACE(flow_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE flow_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "b656927cd70b6667f3c72186ec04f0bf040da3af9e2eac3229264ec95b4755d8"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow SET lock_error_logs = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "ba285edd1c1b1e400e85168ff4f05cf5281fd341096d433c7c0e5712e7726fb0"
}

View File

@@ -22,7 +22,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -0,0 +1,17 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow_workspace_runnables (flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id) VALUES ($1, $2, $3, FALSE, $4) ON CONFLICT DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Int8",
"Varchar"
]
},
"nullable": []
},
"hash": "c35f44f91b08fa57e29a2b4a685706f62e700695810f23108e975dfcd1fee7a3"
}

View File

@@ -19,7 +19,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow SET lock_error_logs = NULL WHERE path = $1 AND workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "d1876c46c0b1aba168efaebd3a056e999c400998eb699d862d718e7ab4c1f427"
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM audit WHERE timestamp <= now() - ($1::bigint::text || ' s')::interval",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
},
"hash": "d8186f0cee285aa50db7626409aec7e0504b068ffa8bb185d9384ce1422fd3d1"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow_workspace_runnables SET runnable_path = REGEXP_REPLACE(runnable_path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1') WHERE runnable_path LIKE ('u/' || $2 || '/%') AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "dc58e5b4715601a93b3c01a2564a4420f232867a23cacb9a62b386f129a86a4b"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE \n FROM \n sqs_trigger \n WHERE \n workspace_id = $1 AND \n path = $2\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "dea056c89313f4facd62cbbc9fa33ba30fa85efcc83fafe4dd7b4e535b96a8d8"
}

View File

@@ -27,7 +27,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -35,7 +35,8 @@
"kafka",
"email",
"nats",
"postgres"
"postgres",
"sqs"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (workspace_id, path, summary, description, dependency_job, draft_only, tag, dedicated_worker, visible_to_runner_only, on_behalf_of_email, value, schema, edited_by, edited_at) \n VALUES ($1, $2, $3, $4, NULL, $5, $6, $7, $8, $9, $10, $11::text::json, $12, now())",
"query": "INSERT INTO flow (workspace_id, path, summary, description, dependency_job, lock_error_logs, draft_only, tag, dedicated_worker, visible_to_runner_only, on_behalf_of_email, value, schema, edited_by, edited_at) \n VALUES ($1, $2, $3, $4, NULL, '', $5, $6, $7, $8, $9, $10, $11::text::json, $12, now())",
"describe": {
"columns": [],
"parameters": {
@@ -21,5 +21,5 @@
},
"nullable": []
},
"hash": "4205d237c123d8d1c9ff2d61118027a80ccc8cd75e9703cb1d014b45f57c2be6"
"hash": "e4f1ee1568ce3c186b569421c6c8a3039f73d04fc53c67c70e67371f06416ef3"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE global_settings SET value = $1 WHERE name = 'teams'",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb"
]
},
"nullable": []
},
"hash": "e565f3b2e51059f563d18a8a9442bcae9640cee7b936820cb46c011222a77ff0"
}

View File

@@ -0,0 +1,104 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n queue_url,\n aws_resource_path,\n message_attributes,\n workspace_id,\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM\n sqs_trigger\n WHERE\n enabled IS TRUE\n AND (last_server_ping IS NULL OR\n last_server_ping < now() - interval '15 seconds'\n )\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "queue_url",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "aws_resource_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "message_attributes",
"type_info": "TextArray"
},
{
"ordinal": 3,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 12,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 14,
"name": "enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
true,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
false
]
},
"hash": "e6adaebcade2e25be800e8b888b23c94caae2421f3cae7c06d6346bd6de1d94a"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id AS \"id!\" FROM v2_job WHERE parent_job = $1 AND workspace_id = $2",
"query": "SELECT id AS \"id!\" FROM v2_job_queue INNER JOIN v2_job USING (id) WHERE parent_job = $1 AND v2_job.workspace_id = $2",
"describe": {
"columns": [
{
@@ -19,5 +19,5 @@
false
]
},
"hash": "c5259e37703c3e48104438bad6e1f3615f4439c090a75e6fde03702a21589b25"
"hash": "eb68469026be39048c5f42a80a2c538fbb54ad269ec81aea89e431a511245a1e"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO metrics (id, value) \n VALUES ('no_uv_usage_py', $1)\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb"
]
},
"nullable": []
},
"hash": "ed318070b26861fda2d591a4356fdbeb6c7fdc965be43bddb010fd8299af1286"
}

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n sqs_trigger \n SET \n aws_resource_path = $1,\n queue_url = $2,\n message_attributes = $3, \n is_flow = $4, \n edited_by = $5, \n email = $6,\n script_path = $7,\n path = $8,\n edited_at = now(), \n error = NULL,\n server_id = NULL\n WHERE \n workspace_id = $9 AND \n path = $10\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"TextArray",
"Bool",
"Varchar",
"Varchar",
"Varchar",
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "f68d23841e0e31cdf8633aaf0f32777e04e4965682e5b37afbe84194b756d5f5"
}

View File

@@ -11,5 +11,5 @@
"remote.autoForwardPorts": true,
"conventionalCommits.scopes": [
"restructring triggers, decoding trigger message on work"
],
]
}

3676
backend/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.463.6"
version = "1.473.0"
authors.workspace = true
edition.workspace = true
@@ -30,7 +30,7 @@ members = [
]
[workspace.package]
version = "1.463.6"
version = "1.473.0"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -59,7 +59,7 @@ flow_testing = ["windmill-worker/flow_testing"]
openidconnect = ["windmill-api/openidconnect"]
cloud = ["windmill-queue/cloud", "windmill-worker/cloud"]
jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"]
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet", "enterprise", "parquet"]
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet", "windmill-common/tantivy", "enterprise", "parquet"]
sqlx = ["windmill-worker/sqlx"]
deno_core = ["windmill-worker/deno_core", "dep:deno_core", "dep:v8"]
kafka = ["windmill-api/kafka"]
@@ -74,6 +74,7 @@ mssql = ["windmill-worker/mssql"]
bigquery = ["windmill-worker/bigquery"]
websocket = ["windmill-api/websocket"]
postgres_trigger = ["windmill-api/postgres_trigger"]
sqs_trigger = ["windmill-api/sqs_trigger"]
python = ["windmill-worker/python"]
smtp = ["windmill-api/smtp", "windmill-common/smtp"]
csharp = ["windmill-worker/csharp"]
@@ -159,12 +160,11 @@ windmill-parser-graphql = { path = "./parsers/windmill-parser-graphql" }
windmill-parser-php = { path = "./parsers/windmill-parser-php" }
windmill-api-client = { path = "./windmill-api-client" }
v8 = "=130.0.7" # Exact version
memchr = "2.7.4"
axum = { version = "^0.7", features = ["multipart"] }
headers = "^0"
hyper = { version = "^1", features = ["full"] }
tokio = { version = "^1.42.0", features = ["full", "tracing"] }
tokio = { version = "^1.42.0", features = ["full", "tracing", "time"] }
tower = "^0"
tower-http = { version = "^0.6", features = ["trace", "cors"] }
tower-cookies = "^0.10"
@@ -173,7 +173,7 @@ serde_json = { version = "^1", features = ["preserve_order", "raw_value"] }
uuid = { version = "^1", features = ["serde", "v4"] }
thiserror = "^2"
anyhow = "^1"
chrono = { version = "0.4.35", features = ["serde"] }
chrono = { version = "=0.4.39", features = ["serde"] }
chrono-tz = "^0.10.1"
tracing = "^0"
tracing-subscriber = { version = "^0", features = ["env-filter", "json"] }
@@ -211,22 +211,28 @@ itertools = "^0"
regex = "^1"
semver = "^1"
deno_fetch = "0.203.0"
deno_tls = "0.166.0"
deno_console = "0.179.0"
deno_url = "0.179.0"
deno_webidl = "0.179.0"
deno_web = "0.210.0"
deno_net = "0.171.0"
deno_core = "0.321.0"
deno_ast = { version = "=0.43.3", features = ["transpiling"] }
deno_permissions = "0.39.0"
v8 = "=130.0.7" # Exact version
deno_fetch = "0.214.0"
deno_tls = "0.177.0"
deno_console = "0.190.0"
deno_url = "0.190.0"
deno_webidl = "0.190.0"
deno_web = "0.221.0"
deno_io = "0.100.0"
deno_net = "0.182.0"
deno_core = "0.336.0"
deno_ast = { version = "=0.44.0", features = ["transpiling"] }
deno_permissions = "0.49.0"
deno_runtime = { version = "0.198.0", features = ["transpile"] }
deno_telemetry = "0.12.0"
deno_error = "=0.5.5"
swc_common = "=0.37.5"
swc_ecma_parser = "=0.149.1"
swc_ecma_ast = "=0.118.2"
swc_ecma_visit = "=0.104.8"
async-recursion = "^1"
base64 = "^0"
@@ -263,9 +269,9 @@ once_cell = "1.17.1"
gosyn = "0.2.6"
bytes = "1.4.0"
gethostname = "0.4.3"
wasm-bindgen = "=0.2.92"
serde-wasm-bindgen = "0.6.5"
wasm-bindgen-test = "0.3.42"
wasm-bindgen = "^0"
serde-wasm-bindgen = "^0"
wasm-bindgen-test = "^0"
convert_case = "0.6.0"
getrandom = "0.2"
tokio-postgres = {version = "^0.7", features = ["array-impls", "with-serde_json-1", "with-chrono-0_4", "with-uuid-1", "with-bit-vec-0_6"]}
@@ -306,6 +312,7 @@ datafusion = "39.0.0"
object_store = { version = "0.10.0", features = ["aws", "azure"] }
openidconnect = { version = "4.0.0-rc.1" }
aws-config = "^1"
aws-sdk-sqs = "1.57.0"
aws-sdk-sts = "^1"
crc = "^3"

View File

@@ -0,0 +1,27 @@
DO
$$
DECLARE
tbl_name text;
policy_exists boolean;
current_sch text;
tbl_names text[] := ARRAY['account', 'app', 'audit', 'capture', 'completed_job', 'flow', 'folder', 'http_trigger', 'queue', 'raw_app', 'resource', 'schedule', 'script', 'usr_to_group', 'variable'];
BEGIN
-- Get the current schema
SELECT current_schema() INTO current_sch;
FOR tbl_name IN SELECT unnest(tbl_names)
LOOP
SELECT EXISTS (
SELECT 1
FROM pg_policies
WHERE schemaname = current_sch
AND tablename = tbl_name
AND policyname = 'admin_policy'
) INTO policy_exists;
IF NOT policy_exists THEN
EXECUTE format('CREATE POLICY admin_policy ON %I.%I TO windmill_admin USING (true);', current_sch, tbl_name);
END IF;
END LOOP;
END;
$$;

View File

@@ -1 +1 @@
5d25cf2cd15c1953794045fd7debea14a33c7519
a165bb74c6c33bdcf618d564498fd4cbb5742451

View File

@@ -0,0 +1,2 @@
-- Add down migration script here
DROP TABLE IF EXISTS sqs_trigger;

View File

@@ -0,0 +1,69 @@
-- Add up migration script here
CREATE TABLE sqs_trigger(
path VARCHAR(255) NOT NULL,
queue_url VARCHAR(255) NOT NULL,
aws_resource_path VARCHAR(255) NOT NULL,
message_attributes TEXT[],
script_path VARCHAR(255) NOT NULL,
is_flow BOOLEAN NOT NULL,
workspace_id VARCHAR(50) NOT NULL,
edited_by VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
edited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
extra_perms JSONB NULL,
error TEXT NULL,
server_id VARCHAR(50) NULL,
last_server_ping TIMESTAMPTZ NULL,
enabled BOOLEAN NOT NULL,
CONSTRAINT PK_sqs_trigger PRIMARY KEY (path,workspace_id),
CONSTRAINT fk_sqs_trigger_workspace FOREIGN KEY (workspace_id)
REFERENCES workspace(id) ON DELETE CASCADE
);
GRANT ALL ON sqs_trigger TO windmill_user;
GRANT ALL ON sqs_trigger TO windmill_admin;
ALTER TABLE sqs_trigger ENABLE ROW LEVEL SECURITY;
CREATE POLICY admin_policy ON sqs_trigger FOR ALL TO windmill_admin USING (true);
CREATE POLICY see_folder_extra_perms_user_select ON sqs_trigger FOR SELECT TO windmill_user
USING (SPLIT_PART(sqs_trigger.path, '/', 1) = 'f' AND SPLIT_PART(sqs_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]));
CREATE POLICY see_folder_extra_perms_user_insert ON sqs_trigger FOR INSERT TO windmill_user
WITH CHECK (SPLIT_PART(sqs_trigger.path, '/', 1) = 'f' AND SPLIT_PART(sqs_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_folder_extra_perms_user_update ON sqs_trigger FOR UPDATE TO windmill_user
USING (SPLIT_PART(sqs_trigger.path, '/', 1) = 'f' AND SPLIT_PART(sqs_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_folder_extra_perms_user_delete ON sqs_trigger FOR DELETE TO windmill_user
USING (SPLIT_PART(sqs_trigger.path, '/', 1) = 'f' AND SPLIT_PART(sqs_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_own ON sqs_trigger FOR ALL TO windmill_user
USING (SPLIT_PART(sqs_trigger.path, '/', 1) = 'u' AND SPLIT_PART(sqs_trigger.path, '/', 2) = current_setting('session.user'));
CREATE POLICY see_member ON sqs_trigger FOR ALL TO windmill_user
USING (SPLIT_PART(sqs_trigger.path, '/', 1) = 'g' AND SPLIT_PART(sqs_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.groups'), ',')::text[]));
CREATE POLICY see_extra_perms_user_select ON sqs_trigger FOR SELECT TO windmill_user
USING (extra_perms ? CONCAT('u/', current_setting('session.user')));
CREATE POLICY see_extra_perms_user_insert ON sqs_trigger FOR INSERT TO windmill_user
WITH CHECK ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
CREATE POLICY see_extra_perms_user_update ON sqs_trigger FOR UPDATE TO windmill_user
USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
CREATE POLICY see_extra_perms_user_delete ON sqs_trigger FOR DELETE TO windmill_user
USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
CREATE POLICY see_extra_perms_groups_select ON sqs_trigger FOR SELECT TO windmill_user
USING (extra_perms ?| regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]);
CREATE POLICY see_extra_perms_groups_insert ON sqs_trigger FOR INSERT TO windmill_user
WITH CHECK (exists(
SELECT key, value FROM jsonb_each_text(extra_perms)
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
AND value::boolean));
CREATE POLICY see_extra_perms_groups_update ON sqs_trigger FOR UPDATE TO windmill_user
USING (exists(
SELECT key, value FROM jsonb_each_text(extra_perms)
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
AND value::boolean));
CREATE POLICY see_extra_perms_groups_delete ON sqs_trigger FOR DELETE TO windmill_user
USING (exists(
SELECT key, value FROM jsonb_each_text(extra_perms)
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
AND value::boolean));

View File

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

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TYPE TRIGGER_KIND ADD VALUE IF NOT EXISTS 'sqs';

View File

@@ -0,0 +1,2 @@
-- Add down migration script here
ALTER TABLE flow DROP COLUMN lock_error_logs;

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TABLE flow ADD COLUMN lock_error_logs TEXT;

View File

@@ -0,0 +1,4 @@
-- Add down migration script here
DROP TRIGGER webhook_change_trigger ON workspace_settings;
DROP FUNCTION notify_webhook_change();

View File

@@ -0,0 +1,15 @@
-- Add up migration script here
CREATE OR REPLACE FUNCTION notify_webhook_change()
RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notify_webhook_change', NEW.workspace_id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER webhook_change_trigger
AFTER UPDATE OF webhook ON workspace_settings
FOR EACH ROW
WHEN (OLD.webhook IS DISTINCT FROM NEW.webhook)
EXECUTE FUNCTION notify_webhook_change();

View File

@@ -0,0 +1,3 @@
-- Add down migration script here
DROP TABLE zombie_job_counter;

View File

@@ -0,0 +1,7 @@
-- Add up migration script here
CREATE TABLE IF NOT EXISTS zombie_job_counter (
job_id UUID PRIMARY KEY REFERENCES v2_job (id) ON DELETE CASCADE,
counter INTEGER NOT NULL DEFAULT 0
);

View File

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

View File

@@ -0,0 +1,37 @@
DO
$do$
DECLARE
current_schema_name TEXT;
BEGIN
-- Get the current schema for the session
SELECT current_schema() INTO current_schema_name;
-- Lock the roles table to prevent race conditions
LOCK TABLE pg_catalog.pg_roles;
EXECUTE format('GRANT USAGE ON SCHEMA %I TO windmill_user', current_schema_name);
EXECUTE format('GRANT USAGE ON SCHEMA %I TO windmill_admin', current_schema_name);
-- Grant privileges dynamically to the current schema
EXECUTE format('GRANT ALL ON ALL TABLES IN SCHEMA %I TO windmill_user', current_schema_name);
EXECUTE format('GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %I TO windmill_user', current_schema_name);
-- Alter default privileges dynamically
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON TABLES TO windmill_user', current_schema_name);
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON SEQUENCES TO windmill_user', current_schema_name);
-- Grant privileges dynamically to the current schema
EXECUTE format('GRANT ALL ON ALL TABLES IN SCHEMA %I TO windmill_admin', current_schema_name);
EXECUTE format('GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA %I TO windmill_admin', current_schema_name);
-- Alter default privileges dynamically
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON TABLES TO windmill_admin', current_schema_name);
EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT ALL ON SEQUENCES TO windmill_admin', current_schema_name);
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Error granting proper permissions to windmill users: %', SQLERRM;
END
$do$;

View File

@@ -0,0 +1 @@
DROP TABLE flow_workspace_runnables;

View File

@@ -0,0 +1,12 @@
CREATE TABLE flow_workspace_runnables (
flow_path VARCHAR(255) NOT NULL,
runnable_path VARCHAR(255) NOT NULL,
script_hash BIGINT NULL,
runnable_is_flow BOOLEAN NOT NULL,
workspace_id VARCHAR(50) NOT NULL,
FOREIGN KEY (workspace_id, flow_path) REFERENCES flow (workspace_id, path) ON DELETE CASCADE
);
CREATE UNIQUE INDEX flow_workspace_without_hash_unique_idx ON flow_workspace_runnables (flow_path, runnable_path, runnable_is_flow, workspace_id) WHERE script_hash IS NULL;
CREATE UNIQUE INDEX flow_workspace_with_hash_unique_idx ON flow_workspace_runnables (flow_path, runnable_path, script_hash, runnable_is_flow, workspace_id) WHERE script_hash IS NOT NULL;
CREATE INDEX flow_workspace_runnable_path_is_flow_idx ON flow_workspace_runnables (runnable_path, runnable_is_flow, workspace_id);

View File

@@ -318,7 +318,7 @@ async fn parse_python_imports_inner(
}
}
const STDIMPORTS: [&str; 302] = [
const STDIMPORTS: [&str; 303] = [
"--future--",
"-abc",
"-aix-support",
@@ -620,5 +620,6 @@ const STDIMPORTS: [&str; 302] = [
"zipapp",
"zipfile",
"zipimport",
"zlib",
"",
];

View File

@@ -96,11 +96,11 @@ pub fn parse_python_signature(
.iter()
.enumerate()
.map(|(i, x)| {
let mut typ = x
let (mut typ, has_default) = x
.as_arg()
.annotation
.as_ref()
.map_or(Typ::Unknown, |e| parse_expr(e));
.map_or((Typ::Unknown, false), |e| parse_expr(e));
let default = if i >= def_arg_start {
params
@@ -138,7 +138,7 @@ pub fn parse_python_signature(
otyp: None,
name: x.as_arg().arg.to_string(),
typ,
has_default: default.is_some(),
has_default: has_default || default.is_some(),
default,
oidx: None,
}
@@ -158,17 +158,27 @@ pub fn parse_python_signature(
}
}
fn parse_expr(e: &Box<Expr>) -> Typ {
fn parse_expr(e: &Box<Expr>) -> (Typ, bool) {
match e.as_ref() {
Expr::Name(ExprName { id, .. }) => parse_typ(id.as_ref()),
Expr::Name(ExprName { id, .. }) => (parse_typ(id.as_ref()), false),
Expr::Attribute(x) => {
if x.value
.as_name_expr()
.is_some_and(|x| x.id.as_str() == "wmill")
{
parse_typ(x.attr.as_str())
(parse_typ(x.attr.as_str()), false)
} else {
Typ::Unknown
(Typ::Unknown, false)
}
}
Expr::BinOp(x) => {
if matches!(
x.right.as_ref(),
Expr::Constant(ExprConstant { value: Constant::None, .. })
) {
(parse_expr(&x.left).0, true)
} else {
(Typ::Unknown, false)
}
}
Expr::Subscript(x) => match x.value.as_ref() {
@@ -193,14 +203,15 @@ fn parse_expr(e: &Box<Expr>) -> Typ {
}
_ => None,
};
Typ::Str(values)
(Typ::Str(values), false)
}
"List" => Typ::List(Box::new(parse_expr(&x.slice))),
_ => Typ::Unknown,
"List" => (Typ::List(Box::new(parse_expr(&x.slice).0)), false),
"Optional" => (parse_expr(&x.slice).0, true),
_ => (Typ::Unknown, false),
},
_ => Typ::Unknown,
_ => (Typ::Unknown, false),
},
_ => Typ::Unknown,
_ => (Typ::Unknown, false),
}
}
@@ -676,4 +687,53 @@ def main(a: list, e: List[int], b: list = [1,2,3,4], c = [1,2,3,4], d = ["a", "b
Ok(())
}
#[test]
fn test_parse_python_sig_9() -> anyhow::Result<()> {
let code = r#"
from typing import Optional
def main(a: str, b: Optional[str], c: str | None): return
"#;
println!(
"{}",
serde_json::to_string(&parse_python_signature(code, None, false)?)?
);
assert_eq!(
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
otyp: None,
name: "a".to_string(),
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None
},
Arg {
otyp: None,
name: "b".to_string(),
typ: Typ::Str(None),
default: None,
has_default: true,
oidx: None
},
Arg {
otyp: None,
name: "c".to_string(),
typ: Typ::Str(None),
default: None,
has_default: true,
oidx: None
},
],
no_main_func: Some(false),
has_preprocessor: Some(false)
}
);
Ok(())
}
}

View File

@@ -4,6 +4,7 @@ use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ};
use windmill_parser_bash::parse_powershell_sig;
use windmill_parser_ts::{parse_deno_signature, parse_expr_for_ids, parse_expr_for_imports};
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_deno_sig() -> anyhow::Result<()> {
let code = "
@@ -146,6 +147,8 @@ export function main(test1?: string, test2: string = \"burkina\",
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_deno_sig_implicit_types() -> anyhow::Result<()> {
let code = "
@@ -224,6 +227,7 @@ export function main(test2 = \"burkina\",
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_deno_types() -> anyhow::Result<()> {
let code = "
@@ -274,6 +278,7 @@ export function main(foo: FooBar, {a, b}: FooBar, {c, d}: FooBar = {a: \"foo\",
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_enum_list() -> anyhow::Result<()> {
let code = "
@@ -305,6 +310,7 @@ export function main(foo: (\"foo\" | \"bar\")[]) {
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_extract_ident() -> anyhow::Result<()> {
let code = "
@@ -324,6 +330,7 @@ fn test_parse_extract_ident() -> anyhow::Result<()> {
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_imports() -> anyhow::Result<()> {
let code = "
@@ -347,6 +354,7 @@ fn test_parse_imports() -> anyhow::Result<()> {
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_imports_dts() -> anyhow::Result<()> {
let code = "
@@ -359,6 +367,7 @@ export type foo = number
Ok(())
}
#[allow(dead_code)]
#[wasm_bindgen_test]
fn test_parse_powershell_sig() -> anyhow::Result<()> {
let code = "

View File

@@ -44,7 +44,7 @@ use windmill_common::{
},
scripts::ScriptLang,
stats_ee::schedule_stats,
utils::{hostname, rd_string, Mode, GIT_VERSION},
utils::{hostname, rd_string, Mode, GIT_VERSION, MODE_AND_ADDONS},
worker::{reload_custom_tags_setting, HUB_CACHE_DIR, TMP_DIR, TMP_LOGS_DIR, WORKER_GROUP},
DB, METRICS_ENABLED,
};
@@ -59,18 +59,15 @@ use tikv_jemallocator::Jemalloc;
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;
#[cfg(feature = "enterprise")]
use windmill_common::METRICS_ADDR;
#[cfg(feature = "parquet")]
use windmill_common::global_settings::OBJECT_STORE_CACHE_CONFIG_SETTING;
use windmill_worker::{
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR, CSHARP_CACHE_DIR,
DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM, GO_BIN_CACHE_DIR, GO_CACHE_DIR,
LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR,
PY312_CACHE_DIR, PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TAR_PY310_CACHE_DIR,
TAR_PY311_CACHE_DIR, TAR_PY312_CACHE_DIR, TAR_PY313_CACHE_DIR, UV_CACHE_DIR,
POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR, PY312_CACHE_DIR, PY313_CACHE_DIR,
RUST_CACHE_DIR, TAR_PY310_CACHE_DIR, TAR_PY311_CACHE_DIR, TAR_PY312_CACHE_DIR,
TAR_PY313_CACHE_DIR, UV_CACHE_DIR,
};
use crate::monitor::{
@@ -118,6 +115,25 @@ where
}
pub fn main() -> anyhow::Result<()> {
// https://github.com/denoland/deno/blob/main/cli/main.rs#L477
#[cfg(feature = "deno_core")]
let unrecognized_v8_flags = deno_core::v8_set_flags(vec![
"--stack-size=1024".to_string(),
// TODO(bartlomieju): I think this can be removed as it's handled by `deno_core`
// and its settings.
// deno_ast removes TypeScript `assert` keywords, so this flag only affects JavaScript
// TODO(petamoriken): Need to check TypeScript `assert` keywords in deno_ast
"--no-harmony-import-assertions".to_string(),
])
.into_iter()
.skip(1)
.collect::<Vec<_>>();
#[cfg(feature = "deno_core")]
if !unrecognized_v8_flags.is_empty() {
println!("Unrecognized V8 flags: {:?}", unrecognized_v8_flags);
}
#[cfg(feature = "deno_core")]
deno_core::JsRuntime::init_platform(None, false);
create_and_run_current_thread_inner(windmill_main())
@@ -222,63 +238,12 @@ async fn windmill_main() -> anyhow::Result<()> {
let hostname = hostname();
let mut enable_standalone_indexer: bool = false;
let mode_and_addons = MODE_AND_ADDONS.clone();
let mode = mode_and_addons.mode;
let mode = std::env::var("MODE")
.map(|x| x.to_lowercase())
.map(|x| {
if &x == "server" {
println!("Binary is in 'server' mode");
Mode::Server
} else if &x == "worker" {
tracing::info!("Binary is in 'worker' mode");
#[cfg(windows)]
{
println!("It is highly recommended to use the agent mode instead on windows (MODE=agent) and to pass a BASE_INTERNAL_URL");
}
Mode::Worker
} else if &x == "agent" {
println!("Binary is in 'agent' mode");
if std::env::var("BASE_INTERNAL_URL").is_err() {
panic!("BASE_INTERNAL_URL is required in agent mode")
}
if std::env::var("JOB_TOKEN").is_err() {
println!("JOB_TOKEN is not passed, hence workers will still need to create permissions for each job and the DATABASE_URL needs to be of a role that can INSERT into the job_perms table")
}
#[cfg(not(feature = "enterprise"))]
{
panic!("Agent mode is only available in the EE, ignoring...");
}
#[cfg(feature = "enterprise")]
Mode::Agent
} else if &x == "indexer" {
tracing::info!("Binary is in 'indexer' mode");
#[cfg(not(feature = "tantivy"))]
{
eprintln!("Cannot start the indexer because tantivy is not included in this binary/image. Make sure you are using the EE image if you want to access the full text search features.");
panic!("Indexer mode requires compiling with the tantivy feature flag.");
}
#[cfg(feature = "tantivy")]
Mode::Indexer
} else if &x == "standalone+search"{
enable_standalone_indexer = true;
println!("Binary is in 'standalone' mode with search enabled");
Mode::Standalone
}
else {
if &x != "standalone" {
eprintln!("mode not recognized, defaulting to standalone: {x}");
} else {
println!("Binary is in 'standalone' mode");
}
Mode::Standalone
}
})
.unwrap_or_else(|_| {
tracing::info!("Mode not specified, defaulting to standalone");
Mode::Standalone
});
if mode == Mode::Standalone {
println!("Running in standalone mode");
}
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))]
println!("jemalloc enabled");
@@ -521,8 +486,7 @@ Windmill Community Edition {GIT_VERSION}
.expect("could not create initial server dir");
#[cfg(feature = "tantivy")]
let should_index_jobs =
mode == Mode::Indexer || (enable_standalone_indexer && mode == Mode::Standalone);
let should_index_jobs = mode == Mode::Indexer || mode_and_addons.indexer;
reload_indexer_config(&db).await;
@@ -725,6 +689,11 @@ Windmill Community Edition {GIT_VERSION}
}
}
},
"notify_webhook_change" => {
let workspace_id = n.payload();
tracing::info!("Webhook change detected, invalidating webhook cache: {}", workspace_id);
windmill_api::webhook_util::WEBHOOK_CACHE.remove(workspace_id);
},
"notify_global_setting_change" => {
tracing::info!("Global setting change detected: {}", n.payload());
match n.payload() {
@@ -901,14 +870,25 @@ Windmill Community Edition {GIT_VERSION}
};
let metrics_f = async {
if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
#[cfg(not(feature = "enterprise"))]
tracing::error!("Metrics are only available in the EE, ignoring...");
let enabled = METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(feature = "enterprise")]
windmill_common::serve_metrics(*METRICS_ADDR, _killpill_phase2_rx, num_workers > 0)
.await;
#[cfg(not(all(feature = "enterprise", feature = "prometheus")))]
if enabled {
tracing::error!("Metrics are only available in the EE, ignoring...");
}
#[cfg(all(feature = "enterprise", feature = "prometheus"))]
if let Err(e) = windmill_common::serve_metrics(
*windmill_common::METRICS_ADDR,
_killpill_phase2_rx,
num_workers > 0,
enabled,
)
.await
{
tracing::error!("Error serving metrics: {e:#}");
}
Ok(()) as anyhow::Result<()>
};
@@ -952,7 +932,11 @@ async fn listen_pg(db: &DB) -> Option<PgListener> {
};
if let Err(e) = listener
.listen_all(vec!["notify_config_change", "notify_global_setting_change"])
.listen_all(vec![
"notify_config_change",
"notify_global_setting_change",
"notify_webhook_change",
])
.await
{
tracing::error!(error = %e, "Could not listen to database");
@@ -1033,10 +1017,8 @@ pub async fn run_workers(
let mut handles = Vec::with_capacity(num_workers as usize);
for x in [
LOCK_CACHE_DIR,
TMP_LOGS_DIR,
UV_CACHE_DIR,
TAR_PIP_CACHE_DIR,
DENO_CACHE_DIR,
DENO_CACHE_DIR_DEPS,
DENO_CACHE_DIR_NPM,
@@ -1049,7 +1031,6 @@ pub async fn run_workers(
TAR_PY311_CACHE_DIR,
TAR_PY312_CACHE_DIR,
TAR_PY313_CACHE_DIR,
PIP_CACHE_DIR,
BUN_BUNDLE_CACHE_DIR,
GO_CACHE_DIR,
GO_BIN_CACHE_DIR,
@@ -1114,9 +1095,12 @@ pub async fn run_workers(
async fn send_delayed_killpill(
tx: &tokio::sync::broadcast::Sender<()>,
max_delay_secs: u64,
mut max_delay_secs: u64,
context: &str,
) {
if max_delay_secs == 0 {
max_delay_secs = 1;
}
// Random delay to avoid all servers/workers shutting down simultaneously
let rd_delay = rand::rng().random_range(0..max_delay_secs);
tracing::info!("Scheduling {context} shutdown in {rd_delay}s");

View File

@@ -34,7 +34,6 @@ use windmill_common::ee::{jobs_waiting_alerts, worker_groups_alerts};
#[cfg(feature = "oauth2")]
use windmill_common::global_settings::OAUTH_SETTING;
use windmill_common::{
auth::JWT_SECRET,
ee::CriticalErrorChannel,
error,
flow_status::{FlowStatus, FlowStatusModule},
@@ -51,6 +50,7 @@ use windmill_common::{
},
indexer::load_indexer_config,
jobs::QueuedJob,
jwt::JWT_SECRET,
oauth2::REQUIRE_PREEXISTING_USER_FOR_OAUTH,
server::load_smtp_config,
tracing_init::JSON_FMT,
@@ -731,6 +731,22 @@ pub async fn delete_expired_items(db: &DB) -> () {
Err(e) => tracing::error!("Error deleting log file: {:?}", e),
}
#[cfg(not(feature = "enterprise"))]
let audit_retention_secs = 1 * 60 * 60 * 24 * 14;
#[cfg(feature = "enterprise")]
let audit_retention_secs = 1 * 60 * 60 * 24 * 365;
if let Err(e) = sqlx::query_scalar!(
"DELETE FROM audit WHERE timestamp <= now() - ($1::bigint::text || ' s')::interval",
audit_retention_secs,
)
.fetch_all(db)
.await
{
tracing::error!("Error deleting audit log on CE: {:?}", e);
}
let job_retention_secs = *JOB_RETENTION_SECS.read().await;
if job_retention_secs > 0 {
match db.begin().await {
@@ -1517,18 +1533,38 @@ pub async fn reload_base_url_setting(db: &DB) -> error::Result<()> {
Ok(())
}
const RESTART_LIMIT: i32 = 3;
async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker_name: &str) {
let mut zombie_jobs_uuid_restart_limit_reached = vec![];
if *RESTART_ZOMBIE_JOBS {
let restarted = sqlx::query!(
"WITH zombie_jobs AS (
UPDATE v2_job_queue q SET running = false, started_at = null
FROM v2_job j, v2_job_runtime r
WHERE j.id = q.id AND j.id = r.id
AND ping < now() - ($1 || ' seconds')::interval
"WITH to_update AS (
SELECT q.id, q.workspace_id, r.ping, COALESCE(zjc.counter, 0) as counter
FROM v2_job_queue q
JOIN v2_job j ON j.id = q.id
JOIN v2_job_runtime r ON r.id = j.id
LEFT JOIN zombie_job_counter zjc ON zjc.job_id = q.id
WHERE ping < now() - ($1 || ' seconds')::interval
AND running = true
AND kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow')
AND same_worker = false
RETURNING q.id, q.workspace_id, ping
AND (zjc.counter IS NULL OR zjc.counter <= $2)
FOR UPDATE of q SKIP LOCKED
),
zombie_jobs AS (
UPDATE v2_job_queue q
SET running = false, started_at = null
FROM to_update tu
WHERE q.id = tu.id AND (tu.counter IS NULL OR tu.counter < $2)
RETURNING q.id, q.workspace_id, ping, tu.counter
),
increment_counter AS (
INSERT INTO zombie_job_counter (job_id, counter)
SELECT id, 1 FROM to_update WHERE counter < $2
ON CONFLICT (job_id) DO UPDATE
SET counter = zombie_job_counter.counter + 1
),
update_concurrency AS (
UPDATE concurrency_counter cc
@@ -1537,8 +1573,9 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
INNER JOIN concurrency_key ck ON ck.job_id = zj.id
WHERE cc.concurrency_id = ck.key
)
SELECT id, workspace_id, ping FROM zombie_jobs",
SELECT id AS \"id!\", workspace_id AS \"workspace_id!\", ping, counter + 1 AS counter FROM to_update",
*ZOMBIE_JOB_TIMEOUT,
RESTART_LIMIT
)
.fetch_all(db)
.await
@@ -1558,22 +1595,61 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
"no last ping".to_string()
};
let url = format!("{}/run/{}?workspace={}", base_url, r.id, r.workspace_id,);
let error_message = format!(
"Zombie job {} on {} ({}) detected, restarting it, {}",
r.id, r.workspace_id, url, last_ping
);
let restart = r.counter.is_none_or(|x| x < RESTART_LIMIT);
let (critical_error_message, restart_message) = if restart {
(
format!(
"Zombie job {} on {} ({}) detected, restarting it ({}/{} attempts), last ping: {}",
r.id,
r.workspace_id,
url,
r.counter.unwrap_or(0) + 1,
RESTART_LIMIT,
last_ping
),
format!(
"Restarted job after not receiving job's ping for too long the {} ({}/{} attempts)\n\n",
last_ping,
r.counter.unwrap_or(0) + 1,
RESTART_LIMIT
)
)
} else {
(
format!(
"Zombie job {} on {} ({}) detected, but restart limit ({}) reached, job will be processed as an error, last ping: {}",
r.id, r.workspace_id, url, RESTART_LIMIT, last_ping
),
format!(
"job's ping was received last at {}, job will be processed as an error since all {} restart attempts failed",
last_ping, RESTART_LIMIT
)
)
};
let _ = sqlx::query!("
let _ = sqlx::query!(
"
INSERT INTO job_logs (job_id, logs)
VALUES ($1, 'Restarted job after not receiving job''s ping for too long the ' || now() || '\n\n')
VALUES ($1, $2)
ON CONFLICT (job_id) DO UPDATE SET logs = job_logs.logs || '\n' || EXCLUDED.logs
WHERE job_logs.job_id = $1",
r.id
r.id,
restart_message
)
.execute(db)
.await;
tracing::error!(error_message);
report_critical_error(error_message, db.clone(), Some(&r.workspace_id), None).await;
tracing::error!(critical_error_message);
report_critical_error(
critical_error_message,
db.clone(),
Some(&r.workspace_id),
None,
)
.await;
if !restart {
zombie_jobs_uuid_restart_limit_reached.push(r.id);
}
}
}
@@ -1648,9 +1724,43 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
.unwrap_or_else(|| vec![])
};
enum ErrorMessage {
RestartLimit,
SameWorker,
RestartDisabled,
}
impl ErrorMessage {
fn to_string(&self) -> String {
match self {
ErrorMessage::RestartLimit => format!("RestartLimit ({})", RESTART_LIMIT),
ErrorMessage::SameWorker => "SameWorker".to_string(),
ErrorMessage::RestartDisabled => "RestartDisabled".to_string(),
}
}
}
let zombie_jobs_restart_limit_reached =
sqlx::query_as::<_, QueuedJob>("SELECT * FROM v2_as_queue WHERE id = ANY($1)")
.bind(&zombie_jobs_uuid_restart_limit_reached[..])
.fetch_all(db)
.await
.ok()
.unwrap_or_else(|| vec![]);
let timeouts = non_restartable_jobs
.into_iter()
.chain(same_worker_timeout_jobs)
.map(|x| (x, ErrorMessage::RestartDisabled))
.chain(
same_worker_timeout_jobs
.into_iter()
.map(|x| (x, ErrorMessage::SameWorker)),
)
.chain(
zombie_jobs_restart_limit_reached
.into_iter()
.map(|x| (x, ErrorMessage::RestartLimit)),
)
.collect::<Vec<_>>();
#[cfg(feature = "prometheus")]
@@ -1658,7 +1768,7 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
QUEUE_ZOMBIE_DELETE_COUNT.inc_by(timeouts.len() as _);
}
for job in timeouts {
for (job, error_kind) in timeouts {
// since the job is unrecoverable, the same worker queue should never be sent anything
let (same_worker_tx_never_used, _same_worker_rx_never_used) =
mpsc::channel::<SameWorkerPayload>(1);
@@ -1693,20 +1803,21 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
};
let last_ping = job.last_ping.clone();
let error_message = format!(
"Job timed out after no ping from job since {} (ZOMBIE_JOB_TIMEOUT: {}, reason: {:?})",
last_ping
.map(|x| x.to_string())
.unwrap_or_else(|| "no ping".to_string()),
*ZOMBIE_JOB_TIMEOUT,
error_kind.to_string()
);
let _ = handle_job_error(
db,
&client,
&job,
0,
None,
error::Error::ExecutionErr(format!(
"Job timed out after no ping from job since {} (ZOMBIE_JOB_TIMEOUT: {}, same_worker: {})",
last_ping
.map(|x| x.to_string())
.unwrap_or_else(|| "no ping".to_string()),
*ZOMBIE_JOB_TIMEOUT,
job.same_worker
)),
error::Error::ExecutionErr(error_message),
true,
same_worker_tx_never_used,
"",

View File

@@ -22,12 +22,12 @@ use windmill_api_client::types::{CreateFlowBody, RawScript};
use windmill_api_client::types::{EditSchedule, NewSchedule, ScriptArgs};
use serde::Serialize;
use windmill_common::auth::JWT_SECRET;
use windmill_common::worker::WORKER_CONFIG;
use windmill_common::{
flow_status::{FlowStatus, FlowStatusModule, RestartedFrom},
flows::{FlowModule, FlowModuleValue, FlowValue, InputTransform},
jobs::{JobKind, JobPayload, RawCode},
jwt::JWT_SECRET,
scripts::{ScriptHash, ScriptLang},
worker::{
MIN_VERSION_IS_AT_LEAST_1_427, MIN_VERSION_IS_AT_LEAST_1_432, MIN_VERSION_IS_AT_LEAST_1_440,
@@ -1015,15 +1015,10 @@ fn spawn_test_worker(
tokio::sync::broadcast::Sender<()>,
tokio::task::JoinHandle<()>,
) {
for x in [
windmill_worker::LOCK_CACHE_DIR,
windmill_worker::GO_BIN_CACHE_DIR,
] {
std::fs::DirBuilder::new()
.recursive(true)
.create(x)
.expect("could not create initial worker dir");
}
std::fs::DirBuilder::new()
.recursive(true)
.create(windmill_worker::GO_BIN_CACHE_DIR)
.expect("could not create initial worker dir");
let (tx, rx) = tokio::sync::broadcast::channel(1);
let db = db.to_owned();
@@ -2905,7 +2900,7 @@ async fn test_flow_lock_all(db: Pool<Postgres>) {
.await
.unwrap()
.into_inner()
.subtype_0
.open_flow
.value
.modules;
modules.into_iter()

View File

@@ -29,6 +29,7 @@ oauth2 = ["dep:async-oauth2"]
http_trigger = ["dep:matchit"]
static_frontend = ["dep:rust-embed"]
postgres_trigger = ["dep:rust-postgres", "dep:pg_escape", "dep:byteorder", "dep:thiserror", "dep:rust_decimal", "dep:rust-postgres-native-tls"]
sqs_trigger = ["dep:aws-sdk-sqs", "dep:thiserror", "dep:aws-config"]
[dependencies]
windmill-queue.workspace = true
@@ -118,4 +119,6 @@ pg_escape = { workspace = true, optional = true }
byteorder = { workspace = true, optional = true }
thiserror = { workspace = true, optional = true }
rust_decimal = { workspace = true, optional = true }
rust-postgres-native-tls = { workspace = true, optional = true}
rust-postgres-native-tls = { workspace = true, optional = true}
aws-sdk-sqs = { workspace = true, optional = true }
aws-config = { workspace = true, optional = true}

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.463.6
version: 1.473.0
title: Windmill API
contact:
@@ -126,6 +126,11 @@ paths:
type: string
- $ref: "#/components/parameters/ResourceName"
- $ref: "#/components/parameters/ActionKind"
- name: all_workspaces
in: query
description: get audit logs for all workspaces
schema:
type: boolean
responses:
"200":
@@ -2611,12 +2616,15 @@ paths:
type: boolean
postgres_used:
type: boolean
sqs_used:
type: boolean
required:
- http_routes_used
- websocket_used
- kafka_used
- nats_used
- postgres_used
- sqs_used
/w/{workspace}/users/list:
get:
summary: list users
@@ -5284,6 +5292,26 @@ paths:
schema:
$ref: "#/components/schemas/FlowVersion"
/w/{workspace}/flows/list_paths_from_workspace_runnable/{runnable_kind}/{path}:
get:
summary: list flow paths from workspace runnable
operationId: listFlowPathsFromWorkspaceRunnable
tags:
- flow
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/RunnableKind"
- $ref: "#/components/parameters/ScriptPath"
responses:
"200":
description: list of flow paths
content:
application/json:
schema:
type: array
items:
type: string
/w/{workspace}/flows/get/v/{version}/p/{path}:
get:
summary: get flow version
@@ -5363,6 +5391,27 @@ paths:
schema:
$ref: "#/components/schemas/Flow"
/w/{workspace}/flows/deployment_status/p/{path}:
get:
summary: get flow deployment status
operationId: getFlowDeploymentStatus
tags:
- flow
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/ScriptPath"
responses:
"200":
description: flow status
content:
application/json:
schema:
type: object
properties:
lock_error_logs:
type: string
/w/{workspace}/flows/get_triggers_count/{path}:
get:
summary: get triggers count of flow
@@ -6183,6 +6232,92 @@ paths:
schema:
type: string
/w/{workspace}/apps_u/upload_s3_file/{path}:
post:
summary: upload s3 file from app
operationId: uploadS3FileFromApp
tags:
- app
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
- name: file_key
in: query
required: false
schema:
type: string
- name: file_extension
in: query
required: false
schema:
type: string
- name: s3_resource_path
in: query
required: false
schema:
type: string
- name: resource_type
in: query
required: false
schema:
type: string
- name: storage
in: query
schema:
type: string
- name: content_type
in: query
schema:
type: string
- name: content_disposition
in: query
schema:
type: string
requestBody:
description: File content
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
"200":
description: file uploaded
content:
application/json:
schema:
type: object
properties:
file_key:
type: string
delete_token:
type: string
required:
- file_key
- delete_token
/w/{workspace}/apps_u/delete_s3_file:
delete:
summary: delete s3 file from app
operationId: deleteS3FileFromApp
tags:
- app
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- name: delete_token
in: query
required: true
schema:
type: string
responses:
"200":
description: file deleted
content:
text/plain:
schema:
type: string
/w/{workspace}/jobs/run/f/{path}:
post:
summary: run flow by path
@@ -8564,6 +8699,196 @@ paths:
schema:
type: string
/w/{workspace}/sqs_triggers/create:
post:
summary: create sqs trigger
operationId: createSqsTrigger
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: new sqs trigger
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NewSqsTrigger"
responses:
"201":
description: sqs trigger created
content:
text/plain:
schema:
type: string
/w/{workspace}/sqs_triggers/update/{path}:
post:
summary: update sqs trigger
operationId: updateSqsTrigger
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
requestBody:
description: updated trigger
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EditSqsTrigger"
responses:
"200":
description: sqs trigger updated
content:
text/plain:
schema:
type: string
/w/{workspace}/sqs_triggers/delete/{path}:
delete:
summary: delete sqs trigger
operationId: deleteSqsTrigger
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: sqs trigger deleted
content:
text/plain:
schema:
type: string
/w/{workspace}/sqs_triggers/get/{path}:
get:
summary: get sqs trigger
operationId: getSqsTrigger
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: sqs trigger deleted
content:
application/json:
schema:
$ref: "#/components/schemas/SqsTrigger"
/w/{workspace}/sqs_triggers/list:
get:
summary: list sqs triggers
operationId: listSqsTriggers
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
required: true
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/PerPage"
- name: path
description: filter by path
in: query
schema:
type: string
- name: is_flow
in: query
schema:
type: boolean
- name: path_start
in: query
schema:
type: string
responses:
"200":
description: sqs trigger list
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SqsTrigger"
/w/{workspace}/sqs_triggers/exists/{path}:
get:
summary: does sqs trigger exists
operationId: existsSqsTrigger
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: sqs trigger exists
content:
application/json:
schema:
type: boolean
/w/{workspace}/sqs_triggers/setenabled/{path}:
post:
summary: set enabled sqs trigger
operationId: setSqsTriggerEnabled
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
requestBody:
description: updated sqs trigger enable
required: true
content:
application/json:
schema:
type: object
properties:
enabled:
type: boolean
required:
- enabled
responses:
"200":
description: sqs trigger enabled set
content:
text/plain:
schema:
type: string
/w/{workspace}/sqs_triggers/test:
post:
summary: test sqs connection
operationId: testSqsConnection
tags:
- sqs_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: test sqs connection
required: true
content:
application/json:
schema:
type: object
properties:
connection:
type: object
required:
- connection
responses:
"200":
description: successfuly connected to sqs
content:
text/plain:
schema:
type: string
/w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}:
get:
summary: check if postgres configuration is set to logical
@@ -9851,6 +10176,7 @@ paths:
kafka_trigger,
nats_trigger,
postgres_trigger,
sqs_trigger
]
responses:
"200":
@@ -9892,6 +10218,7 @@ paths:
kafka_trigger,
nats_trigger,
postgres_trigger,
sqs_trigger
]
requestBody:
description: acl to add
@@ -9944,6 +10271,7 @@ paths:
kafka_trigger,
nats_trigger,
postgres_trigger,
sqs_trigger
]
requestBody:
description: acl to add
@@ -11783,7 +12111,7 @@ components:
AIProvider:
type: string
enum: [openai, anthropic, mistral, deepseek, groq, openrouter, customai]
enum: [openai, anthropic, mistral, deepseek, googleai, groq, openrouter, customai]
AIResource:
type: object
@@ -13166,6 +13494,10 @@ components:
TriggerExtraProperty:
type: object
properties:
path:
type: string
script_path:
type: string
email:
type: string
extra_perms:
@@ -13179,22 +13511,23 @@ components:
edited_at:
type: string
format: date-time
is_flow:
type: boolean
required:
- path
- script_path
- email
- extra_perms
- workspace_id
- edited_by
- edited_at
- is_flow
HttpTrigger:
allOf:
- $ref: "#/components/schemas/TriggerExtraProperty"
type: object
properties:
path:
type: string
script_path:
type: string
route_path:
type: string
static_asset_config:
@@ -13208,8 +13541,6 @@ components:
type: string
required:
- s3
is_flow:
type: boolean
http_method:
type: string
enum:
@@ -13226,15 +13557,7 @@ components:
type: boolean
required:
- path
- edited_by
- edited_at
- script_path
- route_path
- extra_perms
- is_flow
- email
- workspace_id
- is_async
- requires_auth
- http_method
@@ -13357,20 +13680,16 @@ components:
type: number
nats_count:
type: number
sqs_count:
type: number
WebsocketTrigger:
allOf:
- $ref: "#/components/schemas/TriggerExtraProperty"
type: object
properties:
path:
type: string
script_path:
type: string
url:
type: string
is_flow:
type: boolean
server_id:
type: string
last_server_ping:
@@ -13401,15 +13720,7 @@ components:
type: boolean
required:
- path
- edited_by
- edited_at
- script_path
- url
- extra_perms
- is_flow
- email
- workspace_id
- enabled
- filters
- can_return_message
@@ -13519,6 +13830,88 @@ components:
required:
- runnable_result
SqsTrigger:
allOf:
- $ref: "#/components/schemas/TriggerExtraProperty"
type: object
properties:
queue_url:
type: string
aws_resource_path:
type: string
message_attributes:
type: array
items:
type: string
server_id:
type: string
last_server_ping:
type: string
format: date-time
error:
type: string
enabled:
type: boolean
required:
- queue_url
- aws_resource_path
- enabled
NewSqsTrigger:
type: object
properties:
queue_url:
type: string
aws_resource_path:
type: string
message_attributes:
type: array
items:
type: string
path:
type: string
script_path:
type: string
is_flow:
type: boolean
enabled:
type: boolean
required:
- queue_url
- aws_resource_path
- path
- script_path
- is_flow
EditSqsTrigger:
type: object
properties:
queue_url:
type: string
aws_resource_path:
type: string
message_attributes:
type: array
items:
type: string
path:
type: string
script_path:
type: string
is_flow:
type: boolean
enabled:
type: boolean
required:
- queue_url
- aws_resource_path
- path
- script_path
- is_flow
- enabled
Slot:
type: object
properties:
@@ -13600,12 +13993,6 @@ components:
- $ref: "#/components/schemas/TriggerExtraProperty"
type: object
properties:
path:
type: string
script_path:
type: string
is_flow:
type: boolean
enabled:
type: boolean
postgres_resource_path:
@@ -13622,9 +14009,6 @@ components:
type: string
format: date-time
required:
- path
- script_path
- is_flow
- enabled
- postgres_resource_path
- replication_slot_name
@@ -13685,17 +14069,10 @@ components:
- replication_slot_name
KafkaTrigger:
allOf:
- $ref: "#/components/schemas/TriggerExtraProperty"
type: object
properties:
path:
type: string
edited_by:
type: string
edited_at:
type: string
format: date-time
script_path:
type: string
kafka_resource_path:
type: string
group_id:
@@ -13704,16 +14081,6 @@ components:
type: array
items:
type: string
is_flow:
type: boolean
extra_perms:
type: object
additionalProperties:
type: boolean
email:
type: string
workspace_id:
type: string
server_id:
type: string
last_server_ping:
@@ -13725,17 +14092,9 @@ components:
type: boolean
required:
- path
- edited_by
- edited_at
- script_path
- kafka_resource_path
- group_id
- topics
- extra_perms
- is_flow
- email
- workspace_id
- enabled
NewKafkaTrigger:
@@ -13793,17 +14152,10 @@ components:
- is_flow
NatsTrigger:
allOf:
- $ref: "#/components/schemas/TriggerExtraProperty"
type: object
properties:
path:
type: string
edited_by:
type: string
edited_at:
type: string
format: date-time
script_path:
type: string
nats_resource_path:
type: string
use_jetstream:
@@ -13816,16 +14168,6 @@ components:
type: array
items:
type: string
is_flow:
type: boolean
extra_perms:
type: object
additionalProperties:
type: boolean
email:
type: string
workspace_id:
type: string
server_id:
type: string
last_server_ping:
@@ -13837,17 +14179,9 @@ components:
type: boolean
required:
- path
- edited_by
- edited_at
- script_path
- nats_resource_path
- use_jetstream
- subjects
- extra_perms
- is_flow
- email
- workspace_id
- enabled
NewNatsTrigger:
@@ -14134,6 +14468,10 @@ components:
allOf:
- $ref: "../../openflow.openapi.yaml#/components/schemas/OpenFlow"
- $ref: "#/components/schemas/FlowMetadata"
- type: object
properties:
lock_error_logs:
type: string
ExtraPerms:
type: object
@@ -14867,7 +15205,7 @@ components:
CaptureTriggerKind:
type: string
enum: [webhook, http, websocket, kafka, email, nats, postgres]
enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs]
Capture:
type: object

View File

@@ -380,6 +380,7 @@ pub enum AIProvider {
Anthropic,
Mistral,
DeepSeek,
GoogleAI,
Groq,
OpenRouter,
CustomAI,
@@ -389,6 +390,9 @@ impl AIProvider {
pub fn get_openai_compatible_base_url(&self) -> Result<Option<String>> {
match self {
AIProvider::DeepSeek => Ok(Some("https://api.deepseek.com/v1".to_string())),
AIProvider::GoogleAI => Ok(Some(
"https://generativelanguage.googleapis.com/v1beta/openai".to_string(),
)),
AIProvider::Groq => Ok(Some("https://api.groq.com/openai/v1".to_string())),
AIProvider::OpenRouter => Ok(Some("https://openrouter.ai/api/v1".to_string())),
AIProvider::CustomAI => Ok(None),
@@ -409,6 +413,7 @@ impl TryFrom<&str> for AIProvider {
"groq" => Ok(AIProvider::Groq),
"openrouter" => Ok(AIProvider::OpenRouter),
"deepseek" => Ok(AIProvider::DeepSeek),
"googleai" => Ok(AIProvider::GoogleAI),
"customai" => Ok(AIProvider::CustomAI),
_ => Err(Error::BadRequest(format!("Invalid AI provider: {}", s))),
}
@@ -417,7 +422,7 @@ impl TryFrom<&str> for AIProvider {
#[derive(Deserialize, Debug)]
pub struct AIResource {
pub path: String,
pub path: Option<String>,
pub provider: AIProvider,
}
@@ -472,28 +477,34 @@ async fn proxy(
.await?;
if ai_resource.is_none() {
return Err(Error::internal_err("AI resource not configured".to_string()));
return Err(Error::internal_err(
"AI resource not configured".to_string(),
));
}
let ai_resource = serde_json::from_value::<AIResource>(ai_resource.unwrap())
.map_err(|e| Error::BadRequest(e.to_string()))?;
let path = ai_resource.path.unwrap_or("".to_string());
if path.is_empty() {
return Err(Error::BadRequest("Resource path is empty".to_string()));
}
let resource = sqlx::query_scalar!(
"SELECT value
FROM resource
WHERE path = $1 AND workspace_id = $2",
&ai_resource.path,
&path,
&w_id
)
.fetch_optional(&db)
.await?
.ok_or_else(|| {
Error::NotFound(format!(
"Could not find the {:?} resource at path {}, update the resource path in the workspace settings", ai_resource.provider, ai_resource.path
"Could not find the {:?} resource at path {}, update the resource path in the workspace settings", ai_resource.provider, path
))
})?;
(resource, ai_resource.path, ai_resource.provider)
(resource, path, ai_resource.provider)
};
if resource.is_none() {

View File

@@ -21,7 +21,7 @@ use crate::{
job_helpers_ee::{
download_s3_file_internal, get_random_file_name, get_s3_resource,
get_workspace_s3_resource, load_image_preview_internal, upload_file_from_req,
DownloadFileQuery, LoadImagePreviewQuery, UploadFileResponse,
DownloadFileQuery, LoadImagePreviewQuery,
},
users::fetch_api_authed_from_permissioned_as,
};
@@ -51,8 +51,6 @@ use sqlx::{types::Uuid, FromRow};
use std::str;
use windmill_audit::audit_ee::audit_log;
use windmill_audit::ActionKind;
#[cfg(feature = "parquet")]
use windmill_common::s3_helpers::build_object_store_client;
use windmill_common::variables::encrypt;
use windmill_common::{
apps::{AppScriptId, ListAppQuery},
@@ -69,6 +67,8 @@ use windmill_common::{
worker::{to_raw_value, CLOUD_HOSTED},
HUB_BASE_URL,
};
#[cfg(feature = "parquet")]
use windmill_common::{jwt, s3_helpers::build_object_store_client};
use windmill_git_sync::{handle_deployment_metadata, DeployedObject};
use windmill_queue::{push, PushArgs, PushArgsOwned, PushIsolationLevel};
@@ -96,6 +96,7 @@ pub fn unauthed_service() -> Router {
Router::new()
.route("/execute_component/*path", post(execute_component))
.route("/upload_s3_file/*path", post(upload_s3_file_from_app))
.route("/delete_s3_file", delete(delete_s3_file_from_app))
.route("/download_s3_file/*path", get(download_s3_file_from_app))
.route(
"/load_image_preview/*path",
@@ -1497,6 +1498,13 @@ async fn upload_s3_file_from_app() -> Result<()> {
));
}
#[cfg(not(feature = "parquet"))]
async fn delete_s3_file_from_app() -> Result<()> {
return Err(Error::BadRequest(
"This endpoint requires the parquet feature to be enabled".to_string(),
));
}
#[cfg(feature = "parquet")]
#[derive(Debug, Deserialize, Clone)]
struct UploadFileToS3Query {
@@ -1511,6 +1519,24 @@ struct UploadFileToS3Query {
force_viewer_allowed_resources: Option<String>,
}
#[cfg(feature = "parquet")]
#[derive(Serialize, Deserialize)]
struct DeleteTokenClaims {
file_key: String,
on_behalf_of_email: String,
permissioned_as: String,
username: String,
s3_resource_path: Option<String>,
pub exp: usize,
}
#[cfg(feature = "parquet")]
#[derive(Serialize)]
struct AppUploadFileResponse {
file_key: String,
delete_token: String,
}
#[cfg(feature = "parquet")]
async fn upload_s3_file_from_app(
OptAuthed(opt_authed): OptAuthed,
@@ -1518,7 +1544,7 @@ async fn upload_s3_file_from_app(
Path((w_id, path)): Path<(String, StripPath)>,
Query(query): Query<UploadFileToS3Query>,
request: axum::extract::Request,
) -> JsonResult<UploadFileResponse> {
) -> JsonResult<AppUploadFileResponse> {
let policy = if let Some(file_key_regex) = query.force_viewer_file_key_regex {
Some(Policy {
execution_mode: ExecutionMode::Viewer,
@@ -1554,7 +1580,10 @@ async fn upload_s3_file_from_app(
let user_db = UserDB::new(db.clone());
let (s3_resource_opt, file_key) = if policy.as_ref().is_some_and(|p| p.s3_inputs.is_some()) {
let (s3_resource_opt, file_key, on_behalf_of_email, permissioned_as, username) = if policy
.as_ref()
.is_some_and(|p| p.s3_inputs.is_some())
{
let policy = policy.unwrap();
let s3_inputs = policy.s3_inputs.as_ref().unwrap();
@@ -1562,11 +1591,11 @@ async fn upload_s3_file_from_app(
get_on_behalf_details_from_policy_and_authed(&policy, &opt_authed).await?;
let on_behalf_authed = fetch_api_authed_from_permissioned_as(
permissioned_as,
email,
permissioned_as.clone(),
email.clone(),
&w_id,
&db,
Some(username),
Some(username.clone()),
)
.await?;
@@ -1617,6 +1646,9 @@ async fn upload_s3_file_from_app(
.await?,
),
file_key,
email,
permissioned_as,
username,
)
} else {
return Err(Error::BadRequest(
@@ -1640,13 +1672,16 @@ async fn upload_s3_file_from_app(
.await?,
),
file_key,
email,
permissioned_as,
username,
)
}
} else {
let (_, s3_resource_opt) =
get_workspace_s3_resource(&on_behalf_authed, &db, None, "", &w_id, None)
.await?;
(s3_resource_opt, file_key)
(s3_resource_opt, file_key, email, permissioned_as, username)
}
} else {
return Err(Error::BadRequest(
@@ -1672,7 +1707,7 @@ async fn upload_s3_file_from_app(
let (_, s3_resource_opt) =
get_workspace_s3_resource(&on_behalf_authed, &db, None, "", &w_id, None).await?;
(s3_resource_opt, file_key)
(s3_resource_opt, file_key, email, permissioned_as, username)
}
} else {
// backward compatibility (no policy)
@@ -1682,6 +1717,12 @@ async fn upload_s3_file_from_app(
.file_key
.unwrap_or_else(|| get_random_file_name(query.file_extension));
let (on_behalf_of_email, permissioned_as, username) = (
authed.email.clone(),
username_to_permissioned_as(&authed.username),
authed.display_username().to_string(),
);
if let Some(ref s3_resource_path) = query.s3_resource_path {
(
Some(
@@ -1698,12 +1739,21 @@ async fn upload_s3_file_from_app(
.await?,
),
file_key,
on_behalf_of_email,
permissioned_as,
username,
)
} else {
let (_, s3_resource) =
get_workspace_s3_resource(&authed, &db, None, "", &w_id, None).await?;
(s3_resource, file_key)
(
s3_resource,
file_key,
on_behalf_of_email,
permissioned_as,
username,
)
}
} else {
return Err(Error::BadRequest("Missing s3 policy".to_string()));
@@ -1733,7 +1783,81 @@ async fn upload_s3_file_from_app(
upload_file_from_req(s3_client, &file_key, request, options).await?;
return Ok(Json(UploadFileResponse { file_key }));
let delete_token = jwt::encode_with_internal_secret(DeleteTokenClaims {
file_key: file_key.clone(),
on_behalf_of_email,
permissioned_as,
username,
s3_resource_path: query.s3_resource_path,
exp: (chrono::Utc::now() + chrono::Duration::seconds(3600 * 24)).timestamp() as usize,
})
.await?;
return Ok(Json(AppUploadFileResponse { file_key, delete_token }));
}
#[cfg(feature = "parquet")]
#[derive(Deserialize)]
struct DeleteS3FileQuery {
delete_token: String,
}
#[cfg(feature = "parquet")]
async fn delete_s3_file_from_app(
Extension(db): Extension<DB>,
Extension(user_db): Extension<UserDB>,
Path(w_id): Path<String>,
Query(query): Query<DeleteS3FileQuery>,
) -> Result<()> {
let DeleteTokenClaims {
file_key,
on_behalf_of_email,
permissioned_as,
username,
s3_resource_path,
..
} = jwt::decode_with_internal_secret::<DeleteTokenClaims>(&query.delete_token).await?;
let on_behalf_authed = fetch_api_authed_from_permissioned_as(
permissioned_as,
on_behalf_of_email,
&w_id,
&db,
Some(username),
)
.await?;
let s3_resource = if let Some(s3_resource_path) = s3_resource_path {
get_s3_resource(
&on_behalf_authed,
&db,
Some(user_db),
"",
&w_id,
s3_resource_path.as_str(),
None,
None,
)
.await?
} else {
let (_, s3_resource) =
get_workspace_s3_resource(&on_behalf_authed, &db, None, "", &w_id, None).await?;
s3_resource.ok_or(Error::internal_err(
"No files storage resource defined at the workspace level".to_string(),
))?
};
let s3_client = build_object_store_client(&s3_resource).await?;
let path = object_store::path::Path::from(file_key.as_str());
s3_client.delete(&path).await.map_err(|err| {
tracing::error!("Error deleting file: {:?}", err);
Error::internal_err(format!("Error deleting file: {}", err.to_string()))
})?;
Ok(())
}
#[cfg(not(feature = "parquet"))]

View File

@@ -21,7 +21,8 @@ use std::sync::{
use tokio::sync::RwLock;
use windmill_common::{
auth::{get_folders_for_user, get_groups_for_user, JWTAuthClaims, JWT_SECRET},
auth::{get_folders_for_user, get_groups_for_user, JWTAuthClaims},
jwt,
users::{COOKIE_NAME, SUPERADMIN_SECRET_EMAIL},
};
@@ -99,55 +100,44 @@ impl AuthCache {
}
}
_ if token.starts_with("jwt_") => {
let jwt_secret = JWT_SECRET.read().await;
if !jwt_secret.is_empty() {
let jwt_token = token.trim_start_matches("jwt_");
let jwt_token = token.trim_start_matches("jwt_");
let jwt_result = jsonwebtoken::decode::<JWTAuthClaims>(
jwt_token,
&jsonwebtoken::DecodingKey::from_secret(jwt_secret.as_bytes()),
&jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::HS256),
);
let jwt_result = jwt::decode_with_internal_secret::<JWTAuthClaims>(jwt_token).await;
match jwt_result {
Ok(payload) => {
if w_id.is_some_and(|w_id| w_id != payload.claims.workspace_id) {
tracing::error!("JWT auth error: workspace_id mismatch");
return None;
}
let username_override =
username_override_from_label(payload.claims.label);
let authed = crate::db::ApiAuthed {
email: payload.claims.email,
username: payload.claims.username,
is_admin: payload.claims.is_admin,
is_operator: payload.claims.is_operator,
groups: payload.claims.groups,
folders: payload.claims.folders,
scopes: None,
username_override,
};
self.cache.insert(
key,
ExpiringAuthCache {
authed: authed.clone(),
expiry: chrono::Utc
.timestamp_nanos(payload.claims.exp as i64 * 1_000_000_000),
},
);
Some(authed)
}
Err(err) => {
tracing::error!("JWT auth error: {:?}", err);
None
match jwt_result {
Ok(claims) => {
if w_id.is_some_and(|w_id| w_id != claims.workspace_id) {
tracing::error!("JWT auth error: workspace_id mismatch");
return None;
}
let username_override = username_override_from_label(claims.label);
let authed = crate::db::ApiAuthed {
email: claims.email,
username: claims.username,
is_admin: claims.is_admin,
is_operator: claims.is_operator,
groups: claims.groups,
folders: claims.folders,
scopes: None,
username_override,
};
self.cache.insert(
key,
ExpiringAuthCache {
authed: authed.clone(),
expiry: chrono::Utc
.timestamp_nanos(claims.exp as i64 * 1_000_000_000),
},
);
Some(authed)
}
Err(err) => {
tracing::error!("JWT auth error: {:?}", err);
None
}
} else {
tracing::error!("JWT auth error: no jwt secret set");
None
}
}
_ => {

View File

@@ -52,6 +52,7 @@ use crate::{
args::WebhookArgs,
db::{ApiAuthed, DB},
users::fetch_api_authed,
utils::RunnableKind,
};
const KEEP_LAST: i64 = 20;
@@ -98,6 +99,7 @@ pub enum TriggerKind {
Kafka,
Email,
Nats,
Sqs,
Postgres,
}
@@ -110,6 +112,7 @@ impl fmt::Display for TriggerKind {
TriggerKind::Kafka => "kafka",
TriggerKind::Email => "email",
TriggerKind::Nats => "nats",
TriggerKind::Sqs => "sqs",
TriggerKind::Postgres => "postgres",
};
write!(f, "{}", s)
@@ -132,6 +135,14 @@ pub struct KafkaTriggerConfig {
pub group_id: String,
}
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
#[derive(Debug, Serialize, Deserialize)]
pub struct SqsTriggerConfig {
pub queue_url: String,
pub aws_resource_path: String,
pub message_attributes: Option<Vec<String>>,
}
#[cfg(all(feature = "enterprise", feature = "nats"))]
#[derive(Serialize, Deserialize)]
pub struct NatsTriggerConfig {
@@ -171,6 +182,8 @@ enum TriggerConfig {
Postgres(PostgresTriggerConfig),
#[cfg(feature = "websocket")]
Websocket(WebsocketTriggerConfig),
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
Sqs(SqsTriggerConfig),
#[cfg(all(feature = "enterprise", feature = "kafka"))]
Kafka(KafkaTriggerConfig),
#[cfg(all(feature = "enterprise", feature = "nats"))]
@@ -288,8 +301,7 @@ async fn set_config(
#[cfg(feature = "postgres_trigger")]
let nc = if let TriggerKind::Postgres = nc.trigger_kind {
set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await?
}
else {
} else {
nc
};
@@ -350,13 +362,6 @@ struct Capture {
trigger_extra: Option<SqlxJson<Box<serde_json::value::RawValue>>>,
}
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
enum RunnableKind {
Script,
Flow,
}
#[derive(Deserialize)]
struct ListCapturesQuery {
trigger_kind: Option<TriggerKind>,

View File

@@ -32,6 +32,28 @@ async fn current_database(conn: &mut PgConnection) -> Result<String, MigrateErro
.await?)
}
lazy_static::lazy_static! {
pub static ref OVERRIDDEN_MIGRATIONS: std::collections::HashMap<i64, String> = vec![(20221207103910, include_str!(
"../../custom_migrations/create_workspace_without_md5.sql"
).to_string()),
(20240216100535, include_str!(
"../../migrations/20240216100535_improve_policies.up.sql"
).replace("public.", "")),
(20240403083110, include_str!(
"../../migrations/20240403083110_remove_team_id_constraint.up.sql"
).replace("public.", "")),
(20240613150524, include_str!(
"../../migrations/20240613150524_add_job_perms.up.sql"
).replace("public.", "")),
(20250102145420, include_str!(
"../../migrations/20250102145420_more_captures.up.sql"
).replace("public.", "")),
(20241006144414, include_str!(
"../../custom_migrations/grant_all_current_schema.sql"
).to_string()),
].into_iter().collect();
}
struct CustomMigrator {
inner: PoolConnection<Postgres>,
}
@@ -132,12 +154,13 @@ impl Migrate for CustomMigrator {
migration.version,
migration.description
);
if migration.version == 20221207103910 {
tracing::info!("Skipping migration 20221207103910 to avoid using md5");
if let Some(migration_sql) = OVERRIDDEN_MIGRATIONS.get(&migration.version) {
tracing::info!("Using custom migration for version {}", migration.version);
self.inner
.execute(include_str!(
"../../custom_migrations/create_workspace_without_md5.sql"
))
.execute(&**migration_sql)
.await?;
let _ = sqlx::query(
r#"
@@ -528,6 +551,7 @@ async fn v2_finalize(db: &DB) -> Result<(), Error> {
)
.await?;
});
Ok(())
}
@@ -745,6 +769,12 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
.execute(db)
.await?;
});
run_windmill_migration!("audit_timestamps", db, |tx| {
sqlx::query!("CREATE INDEX CONCURRENTLY ix_audit_timestamps ON audit (timestamp DESC)")
.execute(db)
.await?;
});
Ok(())
}

View File

@@ -12,7 +12,7 @@ use crate::db::ApiAuthed;
use crate::triggers::{
get_triggers_count_internal, list_tokens_internal, TriggersCount, TruncatedTokenWithEmail,
};
use crate::utils::WithStarredInfoQuery;
use crate::utils::{RunnableKind, WithStarredInfoQuery};
use crate::{
db::DB,
schedule::clear_schedule,
@@ -59,11 +59,16 @@ pub fn workspaced_service() -> Router {
.route("/get_triggers_count/*path", get(get_triggers_count))
.route("/list_tokens/*path", get(list_tokens))
.route("/get/*path", get(get_flow_by_path))
.route("/deployment_status/p/*path", get(get_deployment_status))
.route("/get/draft/*path", get(get_flow_by_path_w_draft))
.route("/exists/*path", get(exists_flow_by_path))
.route("/list_paths", get(list_paths))
.route("/history/p/*path", get(get_flow_history))
.route("/get_latest_version/*path", get(get_latest_version))
.route(
"/list_paths_from_workspace_runnable/:runnable_kind/*path",
get(list_paths_from_workspace_runnable),
)
.route(
"/history_update/v/:version/p/*path",
post(update_flow_history),
@@ -323,6 +328,28 @@ async fn check_path_conflict<'c>(
return Ok(());
}
async fn list_paths_from_workspace_runnable(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, StripPath)>,
) -> JsonResult<Vec<String>> {
let mut tx = user_db.begin(&authed).await?;
let runnables = sqlx::query_scalar!(
r#"SELECT f.path
FROM flow_workspace_runnables fwr
JOIN flow f
ON fwr.flow_path = f.path AND fwr.workspace_id = f.workspace_id
WHERE fwr.runnable_path = $1 AND fwr.runnable_is_flow = $2 AND fwr.workspace_id = $3"#,
path.to_path(),
matches!(runnable_kind, RunnableKind::Flow),
w_id
)
.fetch_all(&mut *tx)
.await?;
tx.commit().await?;
Ok(Json(runnables))
}
async fn create_flow(
authed: ApiAuthed,
Extension(db): Extension<DB>,
@@ -356,8 +383,8 @@ async fn create_flow(
sqlx::query!(
"INSERT INTO flow (workspace_id, path, summary, description, \
dependency_job, draft_only, tag, dedicated_worker, visible_to_runner_only, on_behalf_of_email, value, schema, edited_by, edited_at)
VALUES ($1, $2, $3, $4, NULL, $5, $6, $7, $8, $9, $10, $11::text::json, $12, now())",
dependency_job, lock_error_logs, draft_only, tag, dedicated_worker, visible_to_runner_only, on_behalf_of_email, value, schema, edited_by, edited_at)
VALUES ($1, $2, $3, $4, NULL, '', $5, $6, $7, $8, $9, $10, $11::text::json, $12, now())",
w_id,
nf.path,
nf.summary,
@@ -683,7 +710,7 @@ async fn update_flow(
sqlx::query!(
"UPDATE flow SET path = $1, summary = $2, description = $3,\
dependency_job = NULL, draft_only = NULL, tag = $4, dedicated_worker = $5, visible_to_runner_only = $6, on_behalf_of_email = $7, \
dependency_job = NULL, lock_error_logs = '', draft_only = NULL, tag = $4, dedicated_worker = $5, visible_to_runner_only = $6, on_behalf_of_email = $7, \
value = $8, schema = $9::text::json, edited_by = $10, edited_at = now()
WHERE path = $11 AND workspace_id = $12",
if is_new_path { flow_path } else { &nf.path }, // if new path, do not rename directly (to avoid flow_version foreign key constraint)
@@ -950,6 +977,31 @@ async fn list_tokens(
list_tokens_internal(&db, &w_id, &path, true).await
}
#[derive(FromRow, Serialize)]
struct DeploymentStatus {
lock_error_logs: Option<String>,
}
async fn get_deployment_status(
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<DeploymentStatus> {
let path = path.to_path();
let mut tx = db.begin().await?;
let status_o: Option<DeploymentStatus> = sqlx::query_as!(
DeploymentStatus,
"SELECT lock_error_logs FROM flow WHERE path = $1 AND workspace_id = $2",
path,
w_id,
)
.fetch_optional(&mut *tx)
.await?;
let status = not_found_if_none(status_o, "DeploymentStatus", path)?;
tx.commit().await?;
Ok(Json(status))
}
async fn get_flow_by_path(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
@@ -961,7 +1013,7 @@ async fn get_flow_by_path(
let flow_o = if query.with_starred_info.unwrap_or(false) {
sqlx::query_as::<_, FlowWithStarred>(
"SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow.on_behalf_of_email, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, favorite.path IS NOT NULL as starred
"SELECT flow.workspace_id, flow.path, flow.lock_error_logs, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow.on_behalf_of_email, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, favorite.path IS NOT NULL as starred
FROM flow
LEFT JOIN favorite
ON favorite.favorite_kind = 'flow'
@@ -978,7 +1030,7 @@ async fn get_flow_by_path(
.await?
} else {
sqlx::query_as::<_, FlowWithStarred>(
"SELECT flow.workspace_id, flow.path, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow.on_behalf_of_email, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, NULL as starred
"SELECT flow.workspace_id, flow.path, flow.lock_error_logs, flow.summary, flow.description, flow.archived, flow.extra_perms, flow.draft_only, flow.dedicated_worker, flow.tag, flow.ws_error_handler_muted, flow.timeout, flow.visible_to_runner_only, flow.on_behalf_of_email, flow_version.schema, flow_version.value, flow_version.created_at as edited_at, flow_version.created_by as edited_by, NULL as starred
FROM flow
LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]
WHERE flow.path = $1 AND flow.workspace_id = $2"

View File

@@ -915,7 +915,16 @@ impl<'a> GetQuery<'a> {
.fetch_queued(db, job_id, workspace_id)
.await?
.map(Job::QueuedJob);
not_found_if_none(job_maybe, "Job", job_id.to_string())
// potential race condition here, if the job was in queue and completed right after the fetch completed, so we need to check one last time
if let Some(job) = job_maybe {
return Ok(job);
} else {
let cjob2 = self
.fetch_completed(db, job_id, workspace_id)
.await?
.map(Job::CompletedJob);
not_found_if_none(cjob2, "Job", job_id.to_string())
}
}
}
}

View File

@@ -39,4 +39,4 @@ pub struct KafkaTrigger {
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
pub enabled: bool,
}
}

View File

@@ -105,6 +105,8 @@ mod settings;
mod slack_approvals;
#[cfg(feature = "smtp")]
mod smtp_server_ee;
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
mod sqs_triggers_ee;
mod static_assets;
mod stripe_ee;
mod teams_ee;
@@ -114,7 +116,7 @@ mod users;
mod users_ee;
mod utils;
mod variables;
mod webhook_util;
pub mod webhook_util;
#[cfg(feature = "websocket")]
mod websocket_triggers;
mod workers;
@@ -319,6 +321,48 @@ pub async fn run_server(
}
};
let sqs_triggers_service = {
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
{
sqs_triggers_ee::workspaced_service()
}
#[cfg(not(all(feature = "enterprise", feature = "sqs_trigger")))]
{
Router::new()
}
};
let websocket_triggers_service = {
#[cfg(feature = "websocket")]
{
websocket_triggers::workspaced_service()
}
#[cfg(not(feature = "websocket"))]
Router::new()
};
let http_triggers_service = {
#[cfg(feature = "http_trigger")]
{
http_triggers::workspaced_service()
}
#[cfg(not(feature = "http_trigger"))]
Router::new()
};
let postgres_triggers_service = {
#[cfg(feature = "postgres_trigger")]
{
postgres_triggers::workspaced_service()
}
#[cfg(not(feature = "postgres_trigger"))]
Router::new()
};
if !*CLOUD_HOSTED {
#[cfg(feature = "websocket")]
{
@@ -337,11 +381,18 @@ pub async fn run_server(
let nats_killpill_rx = rx.resubscribe();
nats_triggers_ee::start_nats_consumers(db.clone(), nats_killpill_rx);
}
#[cfg(feature = "postgres_trigger")]
{
let db_killpill_rx = rx.resubscribe();
postgres_triggers::start_database(db.clone(), db_killpill_rx);
}
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
{
let sqs_killpill_rx = rx.resubscribe();
sqs_triggers_ee::start_sqs(db.clone(), sqs_killpill_rx);
}
}
// build our application with a route
@@ -392,35 +443,12 @@ pub async fn run_server(
.nest("/variables", variables::workspaced_service())
.nest("/workspaces", workspaces::workspaced_service())
.nest("/oidc", oidc_ee::workspaced_service())
.nest("/http_triggers", {
#[cfg(feature = "http_trigger")]
{
http_triggers::workspaced_service()
}
#[cfg(not(feature = "http_trigger"))]
Router::new()
})
.nest("/websocket_triggers", {
#[cfg(feature = "websocket")]
{
websocket_triggers::workspaced_service()
}
#[cfg(not(feature = "websocket"))]
Router::new()
})
.nest("/http_triggers", http_triggers_service)
.nest("/websocket_triggers", websocket_triggers_service)
.nest("/kafka_triggers", kafka_triggers_service)
.nest("/nats_triggers", nats_triggers_service)
.nest("/postgres_triggers", {
#[cfg(feature = "postgres_trigger")]
{
postgres_triggers::workspaced_service()
}
#[cfg(not(feature = "postgres_trigger"))]
Router::new()
}),
.nest("/sqs_triggers", sqs_triggers_service)
.nest("/postgres_triggers", postgres_triggers_service),
)
.nest("/workspaces", workspaces::global_service())
.nest(

View File

@@ -40,4 +40,4 @@ pub struct NatsTrigger {
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
pub enabled: bool,
}
}

View File

@@ -36,11 +36,11 @@ use super::{
use lazy_static::lazy_static;
#[derive(FromRow, Serialize, Deserialize, Debug)]
pub struct Database {
pub struct Postgres {
pub user: String,
pub password: String,
pub host: String,
pub port: u16,
pub port: Option<u16>,
pub dbname: String,
#[serde(default)]
pub sslmode: String,
@@ -113,7 +113,6 @@ pub struct TestPostgres {
pub postgres_resource_path: String,
}
pub async fn test_postgres_connection(
authed: ApiAuthed,
Extension(db): Extension<DB>,
@@ -706,7 +705,7 @@ pub async fn get_publication_info(
let publication_data =
get_publication_scope_and_transaction(&mut connection, &publication_name).await;
let (all_table, transaction_to_track) = match publication_data {
let (all_table, transaction_to_track) = match publication_data {
Ok(pub_data) => pub_data,
Err(Error::SqlErr { error: sqlx::Error::RowNotFound, .. }) => {
return Err(Error::NotFound(
@@ -1457,4 +1456,4 @@ pub async fn is_database_in_logical_level(
};
Ok(Json(is_logical))
}
}

View File

@@ -1,7 +1,7 @@
use crate::{
db::{ApiAuthed, DB},
jobs::{run_flow_by_path_inner, run_script_by_path_inner, RunJobQuery},
resources::get_resource_value_interpolated_internal,
resources::try_get_resource_from_db_as,
users::fetch_api_authed,
};
use chrono::Utc;
@@ -20,18 +20,17 @@ use axum::{
routing::{delete, get, post},
Router,
};
pub use handler::PostgresTrigger;
use handler::{
alter_publication, create_postgres_trigger, create_publication, create_slot,
create_template_script, delete_postgres_trigger, delete_publication, drop_slot_name,
exists_postgres_trigger, get_postgres_trigger, get_publication_info, get_template_script,
is_database_in_logical_level, list_database_publication, list_postgres_triggers,
list_slot_name, set_enabled, test_postgres_connection, update_postgres_trigger, Database,
list_slot_name, set_enabled, test_postgres_connection, update_postgres_trigger, Postgres,
Relations,
};
pub use handler::PostgresTrigger;
use windmill_common::{db::UserDB, error::Error, utils::StripPath};
use windmill_queue::PushArgsOwned;
mod bool;
mod converter;
mod handler;
@@ -55,13 +54,15 @@ pub async fn get_database_connection(
postgres_resource_path: &str,
w_id: &str,
) -> std::result::Result<PgConnection, windmill_common::error::Error> {
let database = get_database_resource(authed, user_db, db, postgres_resource_path, w_id).await?;
let database =
try_get_resource_from_db_as::<Postgres>(authed, user_db, db, postgres_resource_path, w_id)
.await?;
Ok(get_raw_postgres_connection(&database).await?)
}
pub async fn get_raw_postgres_connection(
db: &Database,
db: &Postgres,
) -> std::result::Result<PgConnection, Error> {
let options = {
let sslmode = if !db.sslmode.is_empty() {
@@ -69,12 +70,19 @@ pub async fn get_raw_postgres_connection(
} else {
PgSslMode::Prefer
};
let options = PgConnectOptions::new()
.host(&db.host)
.database(&db.dbname)
.port(db.port)
.ssl_mode(sslmode)
.username(&db.user);
let options = {
let inner_options = PgConnectOptions::new()
.host(&db.host)
.database(&db.dbname)
.ssl_mode(sslmode)
.username(&db.user);
if let Some(port) = db.port {
inner_options.port(port)
} else {
inner_options
}
};
let options = if !db.root_certificate_pem.is_empty() {
options.ssl_root_cert_from_pem(db.root_certificate_pem.as_bytes().to_vec())
@@ -202,39 +210,6 @@ pub fn generate_random_string() -> String {
format!("{}_{}", timestamp, random_part)
}
pub async fn get_database_resource(
authed: ApiAuthed,
user_db: Option<UserDB>,
db: &DB,
database_resource_path: &str,
w_id: &str,
) -> Result<Database, Error> {
let resource = get_resource_value_interpolated_internal(
&authed,
user_db,
&db,
&w_id,
&database_resource_path,
None,
"",
)
.await
.map_err(|_| Error::NotFound("Database resource do not exist".to_string()))?;
let resource = match resource {
Some(resource) => serde_json::from_value::<Database>(resource)?,
None => {
return {
Err(Error::NotFound(
"Database resource do not exist".to_string(),
))
}
}
};
Ok(resource)
}
fn publication_service() -> Router {
Router::new()
.route("/get/:publication_name/*path", get(get_publication_info))

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