windmill-components 1.511.0 → 1.522.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/package/components/AppConnectInner.svelte.d.ts +1 -1
  2. package/package/components/ArgInput.svelte +56 -18
  3. package/package/components/ArgInput.svelte.d.ts +2 -10
  4. package/package/components/AssignableTagsInner.svelte +5 -0
  5. package/package/components/AuthSettings.svelte +4 -2
  6. package/package/components/AuthSettings.svelte.d.ts +1 -0
  7. package/package/components/DBManagerDrawer.svelte +154 -151
  8. package/package/components/DBManagerDrawer.svelte.d.ts +2 -2
  9. package/package/components/DBTable.svelte +3 -3
  10. package/package/components/DBTable.svelte.d.ts +1 -0
  11. package/package/components/DBTableEditor.svelte +7 -7
  12. package/package/components/DBTableEditor.svelte.d.ts +1 -1
  13. package/package/components/DeployWorkspace.svelte +1 -1
  14. package/package/components/DisplayResult.svelte +34 -8
  15. package/package/components/DisplayResult.svelte.d.ts +4 -1
  16. package/package/components/DynSelect.svelte +58 -34
  17. package/package/components/DynSelect.svelte.d.ts +3 -11
  18. package/package/components/EditableSchemaForm.svelte +126 -6
  19. package/package/components/EditableSchemaForm.svelte.d.ts +5 -1
  20. package/package/components/Editor.svelte +1 -1
  21. package/package/components/EditorBar.svelte +82 -4
  22. package/package/components/ErrorOrRecoveryHandler.svelte +76 -8
  23. package/package/components/ErrorOrRecoveryHandler.svelte.d.ts +2 -1
  24. package/package/components/ExploreAssetButton.svelte +14 -4
  25. package/package/components/ExploreAssetButton.svelte.d.ts +1 -0
  26. package/package/components/FlowJobResult.svelte +3 -3
  27. package/package/components/FlowJobResult.svelte.d.ts +1 -0
  28. package/package/components/FlowPreviewContent.svelte +9 -0
  29. package/package/components/FlowPreviewContent.svelte.d.ts +3 -0
  30. package/package/components/FlowPreviewResult.svelte +4 -1
  31. package/package/components/FlowPreviewResult.svelte.d.ts +1 -0
  32. package/package/components/FlowStatusViewer.svelte +2 -1
  33. package/package/components/FlowStatusViewer.svelte.d.ts +3 -0
  34. package/package/components/FlowStatusViewerInner.svelte +23 -3
  35. package/package/components/FlowStatusViewerInner.svelte.d.ts +10 -1
  36. package/package/components/FolderEditor.svelte +1 -1
  37. package/package/components/GitDiffPreview.svelte +14 -18
  38. package/package/components/GitDiffPreview.svelte.d.ts +2 -8
  39. package/package/components/GitHubAppIntegration.svelte +3 -1
  40. package/package/components/IdEditorInput.svelte +25 -22
  41. package/package/components/IdEditorInput.svelte.d.ts +11 -23
  42. package/package/components/InstanceSetting.svelte +7 -2
  43. package/package/components/InstanceSettings.svelte +1 -0
  44. package/package/components/JobLoader.svelte +48 -5
  45. package/package/components/JobLoader.svelte.d.ts +7 -2
  46. package/package/components/Login.svelte +8 -2
  47. package/package/components/MemoryFootprintViewer.svelte +1 -1
  48. package/package/components/ModulePreviewResultViewer.svelte +2 -2
  49. package/package/components/MoveDrawer.svelte.d.ts +2 -2
  50. package/package/components/NextcloudSetting.svelte +84 -0
  51. package/package/components/NextcloudSetting.svelte.d.ts +7 -0
  52. package/package/components/ObjectResourceInput.svelte +3 -2
  53. package/package/components/ObjectResourceInput.svelte.d.ts +1 -0
  54. package/package/components/ParqetCsvTableRenderer.svelte +1 -1
  55. package/package/components/ResourceEditor.svelte +1 -1
  56. package/package/components/ResourcePicker.svelte +8 -1
  57. package/package/components/ResourcePicker.svelte.d.ts +1 -0
  58. package/package/components/ResultStreamDisplay.svelte +5 -0
  59. package/package/components/ResultStreamDisplay.svelte.d.ts +5 -0
  60. package/package/components/RunForm.svelte +9 -1
  61. package/package/components/SchemaForm.svelte +2 -2
  62. package/package/components/SchemaForm.svelte.d.ts +2 -10
  63. package/package/components/ScriptBuilder.svelte +13 -8
  64. package/package/components/ScriptBuilder.svelte.d.ts +1 -1
  65. package/package/components/ScriptEditor.svelte.d.ts +1 -1
  66. package/package/components/ScriptWrapper.svelte +1 -1
  67. package/package/components/ShareModal.svelte.d.ts +1 -1
  68. package/package/components/SimpleAgTable.svelte +2 -0
  69. package/package/components/SimpleAgTable.svelte.d.ts +2 -0
  70. package/package/components/SqlRepl.svelte +21 -7
  71. package/package/components/SqlRepl.svelte.d.ts +2 -2
  72. package/package/components/StringTypeNarrowing.svelte.d.ts +1 -1
  73. package/package/components/WorkerTagSelect.svelte +70 -1
  74. package/package/components/apps/components/display/AppDisplayComponent.svelte +13 -1
  75. package/package/components/apps/components/display/AppText.svelte +2 -2
  76. package/package/components/apps/components/display/dbtable/AppDbExplorer.svelte +8 -1
  77. package/package/components/apps/components/display/dbtable/InsertRow.svelte +5 -4
  78. package/package/components/apps/components/display/dbtable/queries/count.js +11 -1
  79. package/package/components/apps/components/display/dbtable/queries/createTable.d.ts +1 -1
  80. package/package/components/apps/components/display/dbtable/queries/createTable.js +3 -3
  81. package/package/components/apps/components/display/dbtable/queries/delete.js +7 -0
  82. package/package/components/apps/components/display/dbtable/queries/insert.js +2 -0
  83. package/package/components/apps/components/display/dbtable/queries/select.js +14 -0
  84. package/package/components/apps/components/display/dbtable/queries/update.js +7 -0
  85. package/package/components/apps/components/display/dbtable/utils.d.ts +6 -5
  86. package/package/components/apps/components/display/dbtable/utils.js +52 -28
  87. package/package/components/apps/components/display/table/AppAggridExplorerTable.svelte +1 -1
  88. package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte +1 -0
  89. package/package/components/apps/components/display/table/AppAggridInfiniteTable.svelte.d.ts +1 -0
  90. package/package/components/apps/components/display/table/AppAggridTable.svelte +5 -4
  91. package/package/components/apps/components/display/table/AppAggridTable.svelte.d.ts +1 -0
  92. package/package/components/apps/components/display/table/utils.js +7 -4
  93. package/package/components/apps/components/helpers/HiddenComponent.svelte +2 -2
  94. package/package/components/apps/components/helpers/RunnableComponent.svelte +4 -1
  95. package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +2 -1
  96. package/package/components/apps/components/inputs/AppS3FileInput.svelte +2 -2
  97. package/package/components/apps/components/layout/AppDecisionTree.svelte +1 -1
  98. package/package/components/apps/components/layout/AppStepper.svelte +1 -1
  99. package/package/components/apps/components/layout/AppTabs.svelte +1 -1
  100. package/package/components/apps/editor/AppEditorHeader.svelte +13 -2
  101. package/package/components/apps/editor/GridViewer.svelte +1 -0
  102. package/package/components/apps/editor/RunnableJobPanelInner.svelte +2 -1
  103. package/package/components/apps/editor/contextPanel/components/IdEditor.svelte +7 -7
  104. package/package/components/apps/editor/contextPanel/components/IdEditor.svelte.d.ts +7 -19
  105. package/package/components/apps/editor/contextPanel/components/OutputHeader.svelte +8 -12
  106. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte.d.ts +1 -1
  107. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditorDrawer.svelte.d.ts +1 -1
  108. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte.d.ts +1 -1
  109. package/package/components/apps/editor/settingsPanel/DecisionTreeGraphEditor.svelte +3 -3
  110. package/package/components/apps/editor/settingsPanel/decisionTree/DecisionTreePreview.svelte +1 -3
  111. package/package/components/assets/AssetsDropdownButton.svelte +1 -1
  112. package/package/components/assets/JobAssetsViewer.svelte +2 -2
  113. package/package/components/assets/lib.js +4 -0
  114. package/package/components/auditLogs/AuditLogsFilters.svelte +7 -9
  115. package/package/components/common/button/Button.svelte +4 -3
  116. package/package/components/common/button/Button.svelte.d.ts +1 -0
  117. package/package/components/common/confirmationModal/ConfirmationModal.svelte +6 -5
  118. package/package/components/common/confirmationModal/ConfirmationModal.svelte.d.ts +6 -11
  119. package/package/components/common/confirmationModal/asyncConfirmationModal.svelte.d.ts +26 -0
  120. package/package/components/common/confirmationModal/asyncConfirmationModal.svelte.js +50 -0
  121. package/package/components/common/modal/Modal.svelte +2 -5
  122. package/package/components/common/tabs/TabsV2.svelte +2 -1
  123. package/package/components/common/tabs/TabsV2.svelte.d.ts +1 -0
  124. package/package/components/copilot/chat/AIChatManager.svelte.js +61 -7
  125. package/package/components/copilot/chat/ContextTextarea.svelte +1 -1
  126. package/package/components/copilot/chat/script/core.js +28 -29
  127. package/package/components/copilot/chat/shared.d.ts +1 -1
  128. package/package/components/copilot/chat/shared.js +8 -2
  129. package/package/components/custom_ui.d.ts +3 -0
  130. package/package/components/dbOps.d.ts +20 -8
  131. package/package/components/dbOps.js +85 -40
  132. package/package/components/details/DetailPageHeader.svelte +0 -2
  133. package/package/components/flows/content/FlowInput.svelte +5 -0
  134. package/package/components/flows/content/FlowModuleComponent.svelte +1 -0
  135. package/package/components/flows/content/FlowModuleScript.svelte +0 -1
  136. package/package/components/flows/idUtils.js +2 -1
  137. package/package/components/flows/map/FlowModuleSchemaItem.svelte +3 -3
  138. package/package/components/flows/map/FlowModuleSchemaMap.svelte +5 -0
  139. package/package/components/flows/map/InsertModuleButton.svelte +4 -1
  140. package/package/components/flows/propPicker/OutputBadge.svelte +5 -1
  141. package/package/components/flows/propPicker/OutputPickerInner.svelte +9 -5
  142. package/package/components/flows/propPicker/OutputPickerInner.svelte.d.ts +6 -2
  143. package/package/components/flows/propPicker/StepHistory.svelte +4 -1
  144. package/package/components/git_sync/DetectionFlow.svelte +202 -0
  145. package/package/components/git_sync/DetectionFlow.svelte.d.ts +6 -0
  146. package/package/components/git_sync/GitSyncContext.svelte.d.ts +82 -0
  147. package/package/components/git_sync/GitSyncContext.svelte.js +461 -0
  148. package/package/components/git_sync/GitSyncModalManager.svelte +99 -0
  149. package/package/components/git_sync/GitSyncModalManager.svelte.d.ts +18 -0
  150. package/package/components/git_sync/GitSyncRepositoryCard.svelte +339 -0
  151. package/package/components/git_sync/GitSyncRepositoryCard.svelte.d.ts +6 -0
  152. package/package/components/git_sync/GitSyncRepositoryList.svelte +17 -0
  153. package/package/components/git_sync/GitSyncRepositoryList.svelte.d.ts +18 -0
  154. package/package/components/git_sync/GitSyncSection.svelte +89 -0
  155. package/package/components/git_sync/GitSyncSection.svelte.d.ts +3 -0
  156. package/package/components/git_sync/GitSyncSuccessModal.svelte +58 -0
  157. package/package/components/git_sync/GitSyncSuccessModal.svelte.d.ts +7 -0
  158. package/package/components/git_sync/PullWorkspaceModal.svelte +575 -0
  159. package/package/components/git_sync/PullWorkspaceModal.svelte.d.ts +15 -0
  160. package/package/components/git_sync/PushWorkspaceModal.svelte +320 -0
  161. package/package/components/git_sync/PushWorkspaceModal.svelte.d.ts +12 -0
  162. package/package/components/graph/FlowGraphV2.svelte +5 -1
  163. package/package/components/graph/graphBuilder.svelte.js +1 -1
  164. package/package/components/graph/renderers/nodes/AssetNode.svelte +4 -4
  165. package/package/components/icons/AssetDucklakeIcon.svelte +28 -0
  166. package/package/components/icons/AssetDucklakeIcon.svelte.d.ts +9 -0
  167. package/package/components/icons/AssetGenericIcon.svelte +3 -0
  168. package/package/components/icons/DucklakeIcon.svelte +18 -0
  169. package/package/components/icons/DucklakeIcon.svelte.d.ts +6 -0
  170. package/package/components/instanceSettings.js +11 -3
  171. package/package/components/runs/JobPreview.svelte +2 -2
  172. package/package/components/runs/NoWorkerWithTagWarning.svelte +3 -3
  173. package/package/components/runs/RunsFilter.svelte.d.ts +1 -1
  174. package/package/components/schema/FlowPropertyEditor.svelte +3 -2
  175. package/package/components/schema/FlowPropertyEditor.svelte.d.ts +1 -1
  176. package/package/components/schema/PropertyEditor.svelte +0 -2
  177. package/package/components/schema/PropertyEditor.svelte.d.ts +1 -1
  178. package/package/components/schema/SchemaFormDND.svelte +2 -1
  179. package/package/components/schema/SchemaFormDND.svelte.d.ts +2 -0
  180. package/package/components/scriptEditor/LogPanel.svelte +5 -3
  181. package/package/components/scriptEditor/LogPanel.svelte.d.ts +5 -1
  182. package/package/components/select/Select.svelte +7 -4
  183. package/package/components/select/Select.svelte.d.ts +5 -0
  184. package/package/components/select/SelectDropdown.svelte +2 -1
  185. package/package/components/select/SelectDropdown.svelte.d.ts +3 -0
  186. package/package/components/sidebar/changelogs.js +5 -0
  187. package/package/components/table/AutoDataTable.svelte +6 -4
  188. package/package/components/table/AutoDataTable.svelte.d.ts +1 -0
  189. package/package/components/table/DataTable.svelte +12 -10
  190. package/package/components/table/DataTable.svelte.d.ts +1 -0
  191. package/package/components/triggers/TriggerRetriesAndErrorHandler.svelte.d.ts +2 -2
  192. package/package/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte +1 -1
  193. package/package/components/triggers/gcp/GcpTriggerEditorConfigSection.svelte.d.ts +2 -1
  194. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +50 -11
  195. package/package/components/triggers/gcp/utils.js +1 -0
  196. package/package/components/triggers/http/utils.js +1 -1
  197. package/package/components/triggers/kafka/utils.js +1 -1
  198. package/package/components/triggers/mqtt/utils.js +1 -1
  199. package/package/components/triggers/nats/utils.js +1 -1
  200. package/package/components/triggers/postgres/utils.js +1 -1
  201. package/package/components/triggers/sqs/utils.js +1 -1
  202. package/package/components/triggers/utils.js +2 -1
  203. package/package/components/triggers/webhook/WebhooksConfigSection.svelte +24 -26
  204. package/package/components/triggers/webhook/WebhooksPanel.svelte +1 -15
  205. package/package/components/triggers/websocket/utils.js +1 -1
  206. package/package/components/workspaceSettings/AISettings.svelte +52 -36
  207. package/package/components/workspaceSettings/DucklakeSettings.svelte +321 -0
  208. package/package/components/workspaceSettings/DucklakeSettings.svelte.d.ts +23 -0
  209. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte +122 -499
  210. package/package/components/workspaceSettings/GitSyncFilterSettings.svelte.d.ts +8 -10
  211. package/package/consts.js +2 -1
  212. package/package/gen/core/OpenAPI.js +1 -1
  213. package/package/gen/schemas.gen.d.ts +33 -24
  214. package/package/gen/schemas.gen.js +36 -27
  215. package/package/gen/services.gen.d.ts +19 -1
  216. package/package/gen/services.gen.js +38 -0
  217. package/package/gen/types.gen.d.ts +103 -9
  218. package/package/git-sync.d.ts +36 -0
  219. package/package/git-sync.js +1 -0
  220. package/package/hub.d.ts +1 -0
  221. package/package/hubPaths.json +5 -2
  222. package/package/infer.js +3 -2
  223. package/package/script_helpers.d.ts +2 -2
  224. package/package/script_helpers.js +29 -11
  225. package/package/services/JobManager.d.ts +28 -0
  226. package/package/services/JobManager.js +114 -0
  227. package/package/stores.d.ts +1 -1
  228. package/package/utils.d.ts +18 -1
  229. package/package/utils.js +55 -2
  230. package/package.json +13 -12
  231. package/package/components/InitGitRepoPopover.svelte +0 -410
  232. package/package/components/InitGitRepoPopover.svelte.d.ts +0 -13
  233. package/package/components/PullGitRepoPopover.svelte +0 -355
  234. package/package/components/PullGitRepoPopover.svelte.d.ts +0 -18
  235. package/package/inferArgSig.d.ts +0 -35
  236. package/package/inferArgSig.js +0 -191
@@ -2,7 +2,7 @@
2
2
  </script>
3
3
 
4
4
  <script lang="ts">import { run } from 'svelte/legacy';
5
- import { ResourceService, VariableService } from '../gen';
5
+ import { ResourceService, VariableService, WorkspaceService } from '../gen';
6
6
  import { workspaceStore } from '../stores';
7
7
  import { base } from '../base';
8
8
  import ItemPicker from './ItemPicker.svelte';
@@ -20,7 +20,7 @@ import { createEventDispatcher, untrack } from 'svelte';
20
20
  import { sendUserToast } from '../toast';
21
21
  import { getScriptByPath, scriptLangToEditorLang } from '../scripts';
22
22
  import Toggle from './Toggle.svelte';
23
- import { DiffIcon, DollarSign, File, History, Library, Link, Package, Plus, RotateCw, Save, Users } from 'lucide-svelte';
23
+ import { DatabaseIcon, DiffIcon, DollarSign, File, History, Library, Link, Package, Plus, RotateCw, Save, Users } from 'lucide-svelte';
24
24
  import { capitalize, formatS3Object, toCamel } from '../utils';
25
25
  import ScriptVersionHistory from './ScriptVersionHistory.svelte';
26
26
  import ScriptGen from './copilot/ScriptGen.svelte';
@@ -29,6 +29,7 @@ import Popover from './Popover.svelte';
29
29
  import ResourceEditorDrawer from './ResourceEditorDrawer.svelte';
30
30
  import EditorSettings from './EditorSettings.svelte';
31
31
  import S3FilePicker from './S3FilePicker.svelte';
32
+ import DucklakeIcon from './icons/DucklakeIcon.svelte';
32
33
  let { lang, editor, websocketAlive, iconOnly = false, validCode = true, kind = 'script', template = 'script', collabMode = false, collabLive = false, collabUsers = [], scriptPath = undefined, diffEditor = undefined, args, noHistory = false, saveToWorkspace = false, customUi = {}, lastDeployedCode = undefined, diffMode = false, showHistoryDrawer = $bindable(false), right, openAiChat = false } = $props();
33
34
  let contextualVariablePicker = $state();
34
35
  let variablePicker = $state();
@@ -37,6 +38,8 @@ let resourceTypePicker = $state();
37
38
  let variableEditor = $state();
38
39
  let resourceEditor = $state();
39
40
  let s3FilePicker = $state();
41
+ let ducklakePicker = $state();
42
+ let databasePicker = $state();
40
43
  let showContextVarPicker = $derived([
41
44
  'python3',
42
45
  'bash',
@@ -82,12 +85,13 @@ let showResourcePicker = $derived([
82
85
  'rust',
83
86
  'csharp',
84
87
  'nu',
85
- 'java',
86
- 'duckdb'
88
+ 'java'
87
89
  // for related places search: ADD_NEW_LANG
88
90
  ].includes(lang ?? ''));
89
91
  let showS3Picker = $derived(['duckdb', 'python3'].includes(lang ?? '') ||
90
92
  ['typescript', 'javascript'].includes(scriptLangToEditorLang(lang)));
93
+ let showDucklakePicker = $derived(['duckdb'].includes(lang ?? ''));
94
+ let showDatabasePicker = $derived(['duckdb'].includes(lang ?? ''));
91
95
  let showResourceTypePicker = $derived(['typescript', 'javascript'].includes(scriptLangToEditorLang(lang)) ||
92
96
  lang === 'python3' ||
93
97
  lang === 'php');
@@ -551,6 +555,48 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
551
555
  <ResourceEditorDrawer bind:this={resourceEditor} on:refresh={resourcePicker.openDrawer} />
552
556
  <VariableEditor bind:this={variableEditor} on:create={variablePicker.openDrawer} />
553
557
 
558
+ {#if showDucklakePicker}
559
+ <ItemPicker
560
+ bind:this={ducklakePicker}
561
+ pickCallback={async (_, name) => {
562
+ const connStr = name == 'main' ? 'ducklake' : `ducklake://${name}`
563
+ editor?.insertAtCursor(`ATTACH '${connStr}' AS dl; USE dl;\n`)
564
+ }}
565
+ tooltip="Attach a Ducklake in your DuckDB script. Ducklake allows you to manipulate large data on S3 blob files through a traditional SQL interface."
566
+ documentationLink="https://www.windmill.dev/docs/core_concepts/ducklake"
567
+ itemName="ducklake"
568
+ loadItems={async () =>
569
+ (await WorkspaceService.listDucklakes({ workspace: $workspaceStore ?? 'NO_W' })).map(
570
+ (path) => ({ path })
571
+ )}
572
+ />
573
+ {/if}
574
+
575
+ {#if showDatabasePicker}
576
+ <ItemPicker
577
+ bind:this={databasePicker}
578
+ pickCallback={(path, _, resType) => {
579
+ if (!editor) return
580
+ if (lang == 'duckdb') {
581
+ let t = { postgresql: 'postgres', mysql: 'mysql', bigquery: 'bigquery' }[resType]
582
+ editor.insertAtCursor(`ATTACH 'res://${path}' AS db (TYPE ${t});`)
583
+ }
584
+ sendUserToast(`${path} inserted at cursor`)
585
+ }}
586
+ tooltip="Attach a database resource in your script. This allows you to query data from the database using SQL."
587
+ documentationLink="https://www.windmill.dev/docs/core_concepts/resources_and_types"
588
+ itemName="Database"
589
+ buttons={{ 'Edit/View': (x) => resourceEditor?.initEdit(x) }}
590
+ extraField="description"
591
+ extraField2="resource_type"
592
+ loadItems={async () =>
593
+ await ResourceService.listResource({
594
+ workspace: $workspaceStore ?? 'NO_W',
595
+ resourceType: 'postgresql,mysql,bigquery'
596
+ })}
597
+ ></ItemPicker>
598
+ {/if}
599
+
554
600
  <S3FilePicker
555
601
  bind:this={s3FilePicker}
556
602
  readOnlyMode={false}
@@ -664,6 +710,38 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
664
710
  </Button>
665
711
  {/if}
666
712
 
713
+ {#if showDatabasePicker && customUi?.database != false}
714
+ <Button
715
+ aiId="editor-bar-add-database"
716
+ aiDescription="Add database"
717
+ title="Add database"
718
+ color="light"
719
+ on:click={() => databasePicker?.openDrawer()}
720
+ size="xs"
721
+ btnClasses="!font-medium text-tertiary"
722
+ spacingSize="md"
723
+ startIcon={{ icon: DatabaseIcon }}
724
+ {iconOnly}
725
+ >+Database
726
+ </Button>
727
+ {/if}
728
+
729
+ {#if showDucklakePicker && customUi?.ducklake != false}
730
+ <Button
731
+ aiId="editor-bar-use-ducklake"
732
+ aiDescription="Use Ducklake"
733
+ title="Use Ducklake"
734
+ color="light"
735
+ on:click={() => ducklakePicker?.openDrawer()}
736
+ size="xs"
737
+ btnClasses="!font-medium text-tertiary"
738
+ spacingSize="md"
739
+ startIcon={{ icon: DucklakeIcon }}
740
+ {iconOnly}
741
+ >+Ducklake
742
+ </Button>
743
+ {/if}
744
+
667
745
  {#if customUi?.reset != false}
668
746
  <Button
669
747
  aiId="editor-bar-reset-content"
@@ -7,18 +7,21 @@ import { base } from '../base';
7
7
  import { enterpriseLicense, workspaceStore } from '../stores';
8
8
  import MsTeamsIcon from './icons/MSTeamsIcon.svelte';
9
9
  import { emptySchema, emptyString, sendUserToast, tryEvery } from '../utils';
10
+ import Description from './Description.svelte';
11
+ import MultiSelect from './select/MultiSelect.svelte';
10
12
  import { FlowService, JobService, ScriptService, WorkspaceService } from '../gen';
11
13
  import { inferArgs } from '../infer';
12
14
  import { hubBaseUrlStore } from '../stores';
13
15
  import { CheckCircle2, Loader2, RotateCw, XCircle, RefreshCcw } from 'lucide-svelte';
14
16
  import { hubPaths } from '../hub';
17
+ import { isCloudHosted } from '../cloud';
15
18
  const slackRecoveryHandler = hubPaths.slackRecoveryHandler;
16
19
  const slackHandlerScriptPath = hubPaths.slackErrorHandler;
17
20
  const slackSuccessHandler = hubPaths.slackSuccessHandler;
18
21
  const teamsRecoveryHandler = hubPaths.teamsRecoveryHandler;
19
22
  const teamsHandlerScriptPath = hubPaths.teamsErrorHandler;
20
23
  const teamsSuccessHandler = hubPaths.teamsSuccessHandler;
21
- let { errorOrRecovery, isEditable, toggleText = 'Enable', showScriptHelpText = false, handlerSelected = $bindable(), handlerPath = $bindable(), handlerExtraArgs = $bindable(), customScriptTemplate, customHandlerKind = $bindable('script'), customTabTooltip } = $props();
24
+ let { errorOrRecovery, isEditable, toggleText = 'Enable', showScriptHelpText = false, handlerSelected = $bindable('custom'), handlerPath = $bindable(), handlerExtraArgs = $bindable(), customScriptTemplate, customHandlerKind = $bindable('script'), customTabTooltip, } = $props();
22
25
  let customHandlerSchema = $state();
23
26
  let slackHandlerSchema = $state();
24
27
  let isFetching = $state(false);
@@ -27,6 +30,8 @@ let teams_team_name = $state(undefined);
27
30
  let workspaceConnectedToSlack = $state(undefined);
28
31
  let workspaceConnectedToTeams = $state(undefined);
29
32
  let connectionTestJob = $state();
33
+ const EMAIL_RECIPIENTS_KEY = 'email_recipients';
34
+ const CHANNEL_KEY = 'channel';
30
35
  async function loadSlackResources() {
31
36
  const settings = await WorkspaceService.getSettings({ workspace: $workspaceStore });
32
37
  if (!emptyString(settings.slack_name) && !emptyString(settings.slack_team_id)) {
@@ -166,6 +171,12 @@ function isTeamsHandler(scriptPath) {
166
171
  return scriptPath.startsWith('hub/') && scriptPath.endsWith('/schedule-success-handler-teams');
167
172
  }
168
173
  }
174
+ function isEmailHandler(scriptPath) {
175
+ if (!scriptPath) {
176
+ return false;
177
+ }
178
+ return scriptPath.startsWith('hub/') && scriptPath.endsWith('/workspace-or-error-handler-email');
179
+ }
169
180
  $effect(() => {
170
181
  if ($workspaceStore) {
171
182
  loadSlackResources();
@@ -181,21 +192,27 @@ $effect(() => {
181
192
  }
182
193
  });
183
194
  let lastHandlerSelected = $state(undefined);
184
- let channelCache = $state({
195
+ let handlerCache = $state({
185
196
  slack: undefined,
186
- teams: undefined
197
+ teams: undefined,
198
+ email: undefined
187
199
  });
188
200
  $effect(() => {
189
201
  if (lastHandlerSelected !== handlerSelected && lastHandlerSelected !== undefined) {
190
- if (lastHandlerSelected === 'teams' || lastHandlerSelected === 'slack') {
191
- channelCache[lastHandlerSelected] = handlerExtraArgs['channel'];
202
+ if (lastHandlerSelected != 'custom') {
203
+ const key = lastHandlerSelected === 'email' ? EMAIL_RECIPIENTS_KEY : CHANNEL_KEY;
204
+ handlerCache[lastHandlerSelected] = handlerExtraArgs[key];
192
205
  }
193
206
  if (handlerSelected === 'custom') {
194
- handlerExtraArgs['channel'] = '';
207
+ handlerExtraArgs[CHANNEL_KEY] = '';
208
+ handlerExtraArgs[EMAIL_RECIPIENTS_KEY] = [];
195
209
  handlerPath = undefined;
196
210
  }
211
+ else if (handlerSelected === 'email') {
212
+ handlerExtraArgs[EMAIL_RECIPIENTS_KEY] = handlerCache[handlerSelected] ?? [];
213
+ }
197
214
  else {
198
- handlerExtraArgs['channel'] = channelCache[handlerSelected] ?? '';
215
+ handlerExtraArgs[CHANNEL_KEY] = handlerCache[handlerSelected] ?? '';
199
216
  }
200
217
  }
201
218
  lastHandlerSelected = handlerSelected;
@@ -204,6 +221,7 @@ $effect(() => {
204
221
  handlerPath &&
205
222
  !isSlackHandler(handlerPath) &&
206
223
  !isTeamsHandler(handlerPath) &&
224
+ !isEmailHandler(handlerPath) &&
207
225
  loadHandlerScriptArgs(handlerPath, [
208
226
  'path',
209
227
  'workspace_id',
@@ -242,12 +260,18 @@ $effect(() => {
242
260
  'slack'
243
261
  ]).then((schema) => (slackHandlerSchema = schema));
244
262
  });
263
+ $effect(() => {
264
+ if (handlerSelected === 'email') {
265
+ handlerPath = hubPaths.emailErrorHandler;
266
+ }
267
+ });
245
268
  </script>
246
269
 
247
270
  <div>
248
271
  <Tabs bind:selected={handlerSelected} class="mt-2 mb-4">
249
272
  <Tab value="slack" disabled={!isEditable}>Slack</Tab>
250
273
  <Tab value="teams" disabled={!isEditable}>Teams</Tab>
274
+ <Tab value="email" disabled={!isEditable}>Email</Tab>
251
275
  <Tab value="custom" disabled={!isEditable}>
252
276
  Custom
253
277
  {@render customTabTooltip?.()}
@@ -274,8 +298,10 @@ $effect(() => {
274
298
  size="xs"
275
299
  href={customScriptTemplate}
276
300
  disabled={!isEditable}
277
- target="_blank">Create from template</Button
301
+ target="_blank"
278
302
  >
303
+ Create from template
304
+ </Button>
279
305
  {/if}
280
306
  </div>
281
307
  {#if showScriptHelpText}
@@ -503,4 +529,46 @@ $effect(() => {
503
529
  {/if}
504
530
  {/if}
505
531
  {/if}
532
+ {:else if handlerSelected === 'email'}
533
+ {#if isCloudHosted()}
534
+ <Alert type="info" title="Email notifications are not available in Cloud">
535
+ Email notifications for trigger failures are only available in self-hosted Windmill instances.
536
+ </Alert>
537
+ {:else}
538
+ <div class="flex flex-col gap-4 my-4">
539
+ <Description>
540
+ Configure email addresses to receive notifications when jobs fail. This feature requires
541
+ SMTP to be configured.
542
+ </Description>
543
+ </div>
544
+ <div class="flex flex-col gap-2 my-4">
545
+ <MultiSelect
546
+ items={[] as { label: string; value: string }[]}
547
+ bind:value={
548
+ () => handlerExtraArgs[EMAIL_RECIPIENTS_KEY] ?? [],
549
+ (recipients) => (handlerExtraArgs[EMAIL_RECIPIENTS_KEY] = recipients)
550
+ }
551
+ placeholder="Enter email addresses..."
552
+ onCreateItem={(email) => {
553
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
554
+ if (!emailRegex.test(email)) {
555
+ sendUserToast('Invalid email format', true)
556
+ return
557
+ }
558
+ const currentArray = handlerExtraArgs[EMAIL_RECIPIENTS_KEY] ?? []
559
+ handlerExtraArgs[EMAIL_RECIPIENTS_KEY] = [...currentArray, email]
560
+ }}
561
+ class="w-full"
562
+ />
563
+ {#if handlerExtraArgs[EMAIL_RECIPIENTS_KEY]?.length > 0}
564
+ <span class="text-sm text-tertiary">
565
+ {handlerExtraArgs[EMAIL_RECIPIENTS_KEY]?.length} email{handlerExtraArgs[
566
+ EMAIL_RECIPIENTS_KEY
567
+ ]?.length === 1
568
+ ? ''
569
+ : 's'} configured
570
+ </span>
571
+ {/if}
572
+ </div>
573
+ {/if}
506
574
  {/if}
@@ -1,9 +1,10 @@
1
+ import type { ErrorHandler } from '../gen/types.gen';
1
2
  interface Props {
2
3
  errorOrRecovery: 'error' | 'recovery' | 'success';
3
4
  isEditable: boolean;
4
5
  toggleText?: string;
5
6
  showScriptHelpText?: boolean;
6
- handlerSelected: 'custom' | 'slack' | 'teams';
7
+ handlerSelected: ErrorHandler;
7
8
  handlerPath: string | undefined;
8
9
  handlerExtraArgs: Record<string, any>;
9
10
  customScriptTemplate: string;
@@ -1,5 +1,6 @@
1
1
  <script module lang="ts">export function assetCanBeExplored(asset, _resourceMetadata) {
2
- return (asset.kind === 's3object' ||
2
+ return (asset.kind === 'ducklake' ||
3
+ asset.kind === 's3object' ||
3
4
  (asset.kind === 'resource' && isDbType(_resourceMetadata?.resource_type)));
4
5
  }
5
6
  </script>
@@ -12,12 +13,13 @@ import S3FilePicker from './S3FilePicker.svelte';
12
13
  import { userStore } from '../stores';
13
14
  import { isS3Uri } from '../utils';
14
15
  import { Database, File } from 'lucide-svelte';
15
- const { asset, _resourceMetadata, s3FilePicker, dbManagerDrawer, onClick, class: className = '', noText = false, buttonVariant = 'border', btnClasses = '' } = $props();
16
+ import DucklakeIcon from './icons/DucklakeIcon.svelte';
17
+ const { asset, _resourceMetadata, s3FilePicker, dbManagerDrawer, onClick, class: className = '', noText = false, buttonVariant = 'border', btnClasses = '', disabled = false } = $props();
16
18
  const assetUri = $derived(formatAsset(asset));
17
19
  </script>
18
20
 
19
21
  <Button
20
- disabled={$userStore?.operator}
22
+ disabled={$userStore?.operator || disabled}
21
23
  size="xs"
22
24
  variant={buttonVariant}
23
25
  spacingSize="xs2"
@@ -25,9 +27,15 @@ const assetUri = $derived(formatAsset(asset));
25
27
  {btnClasses}
26
28
  on:click={async () => {
27
29
  if (asset.kind === 'resource' && isDbType(_resourceMetadata?.resource_type)) {
28
- dbManagerDrawer?.openDrawer(_resourceMetadata.resource_type, asset.path)
30
+ dbManagerDrawer?.openDrawer({
31
+ type: 'database',
32
+ resourceType: _resourceMetadata.resource_type,
33
+ resourcePath: asset.path
34
+ })
29
35
  } else if (asset.kind === 's3object' && isS3Uri(assetUri)) {
30
36
  s3FilePicker?.open(assetUri)
37
+ } else if (asset.kind === 'ducklake') {
38
+ dbManagerDrawer?.openDrawer({ type: 'ducklake', ducklake: asset.path })
31
39
  }
32
40
  onClick?.()
33
41
  }}
@@ -36,5 +44,7 @@ const assetUri = $derived(formatAsset(asset));
36
44
  <span class:hidden={noText}>Explore</span> <File size={18} />
37
45
  {:else if asset.kind === 'resource'}
38
46
  <span class:hidden={noText}>Manage</span> <Database size={18} />
47
+ {:else if asset.kind === 'ducklake'}
48
+ <span class:hidden={noText}>Manage</span> <DucklakeIcon size={18} />
39
49
  {/if}
40
50
  </Button>
@@ -17,6 +17,7 @@ type $$ComponentProps = {
17
17
  noText?: boolean;
18
18
  buttonVariant?: ButtonType.Variant;
19
19
  btnClasses?: string;
20
+ disabled?: boolean;
20
21
  };
21
22
  declare const ExploreAssetButton: import("svelte").Component<$$ComponentProps, {}, "">;
22
23
  type ExploreAssetButton = ReturnType<typeof ExploreAssetButton>;
@@ -7,7 +7,7 @@ import DrawerContent from './common/drawer/DrawerContent.svelte';
7
7
  import { Drawer } from './common';
8
8
  import AllFlowLogs from './AllFlowLogs.svelte';
9
9
  import { untrack } from 'svelte';
10
- let { waitingForExecutor = false, result, logs = $bindable(), col = false, noBorder = false, loading, filename = undefined, jobId = undefined, tag = undefined, workspaceId = undefined, refreshLog = false, durationStates, downloadLogs = true, tagLabel = undefined } = $props();
10
+ let { waitingForExecutor = false, result, result_stream, logs = $bindable(), col = false, noBorder = false, loading, filename = undefined, jobId = undefined, tag = undefined, workspaceId = undefined, refreshLog = false, durationStates, downloadLogs = true, tagLabel = undefined } = $props();
11
11
  let lastJobId = $state(undefined);
12
12
  let drawer = $state(undefined);
13
13
  let iteration = 0;
@@ -62,8 +62,8 @@ $effect(() => {
62
62
  >
63
63
  <div class="bg-surface {col ? '' : 'max-h-80'} p-1 overflow-auto relative">
64
64
  <span class="text-tertiary">Result</span>
65
- {#if result !== undefined}
66
- <DisplayResult {workspaceId} {jobId} {filename} {result} />
65
+ {#if result !== undefined || result_stream !== undefined}
66
+ <DisplayResult {workspaceId} {jobId} {filename} {result} {result_stream} />
67
67
  {:else if loading}
68
68
  <Loader2 class="animate-spin" />
69
69
  {:else}
@@ -3,6 +3,7 @@ import type { Writable } from 'svelte/store';
3
3
  interface Props {
4
4
  waitingForExecutor?: boolean;
5
5
  result: any;
6
+ result_stream?: string;
6
7
  logs: string | undefined;
7
8
  col?: boolean;
8
9
  noBorder?: boolean;
@@ -427,6 +427,14 @@ export function flowHasChanged() {
427
427
  savedArgs = previewArgs.val
428
428
  }}
429
429
  bind:isValid
430
+ helperScript={flowStore.val.schema?.['x-windmill-dyn-select-code'] &&
431
+ flowStore.val.schema?.['x-windmill-dyn-select-lang']
432
+ ? {
433
+ type: 'inline',
434
+ code: flowStore.val.schema['x-windmill-dyn-select-code'] as string,
435
+ lang: flowStore.val.schema['x-windmill-dyn-select-lang'] as ScriptLang
436
+ }
437
+ : undefined}
430
438
  />
431
439
  </div>
432
440
  {/key}
@@ -494,6 +502,7 @@ export function flowHasChanged() {
494
502
  bind:rightColumnSelect
495
503
  bind:isOwner
496
504
  {render}
505
+ {customUi}
497
506
  />
498
507
  {:else}
499
508
  <div class="italic text-tertiary h-full grow"> Flow status will be displayed here </div>
@@ -20,6 +20,9 @@ interface Props {
20
20
  render?: boolean;
21
21
  onJobDone?: () => void;
22
22
  upToId?: string | undefined;
23
+ customUi?: {
24
+ tagLabel?: string | undefined;
25
+ };
23
26
  }
24
27
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
25
28
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -4,7 +4,7 @@ import FlowPreviewStatus from './preview/FlowPreviewStatus.svelte';
4
4
  import FlowStatusWaitingForEvents from './FlowStatusWaitingForEvents.svelte';
5
5
  import { emptyString } from '../utils';
6
6
  import Badge from './common/badge/Badge.svelte';
7
- let { job, workspaceId, isOwner, hideFlowResult, hideDownloadLogs, localDurationStatuses, innerModules, suspendStatus, hideJobId, extra } = $props();
7
+ let { job, workspaceId, isOwner, hideFlowResult, hideDownloadLogs, localDurationStatuses, innerModules, suspendStatus, hideJobId, extra, result_streams } = $props();
8
8
  </script>
9
9
 
10
10
  <FlowPreviewStatus {job} {hideJobId} {extra} />
@@ -76,6 +76,9 @@ let { job, workspaceId, isOwner, hideFlowResult, hideDownloadLogs, localDuration
76
76
  <Loader2 class="animate-spin mt-0.5" /></span
77
77
  ></div
78
78
  >
79
+ {#if mod.job && result_streams?.[mod.job]}
80
+ <pre class="text-xs text-primary">{result_streams?.[mod.job]}</pre>
81
+ {/if}
79
82
  {/if}
80
83
  {/each}
81
84
  </div>
@@ -15,6 +15,7 @@ interface Props {
15
15
  }>>;
16
16
  hideJobId?: boolean;
17
17
  extra?: import('svelte').Snippet;
18
+ result_streams?: Record<string, string | undefined>;
18
19
  }
19
20
  declare const FlowPreviewResult: import("svelte").Component<Props, {}, "">;
20
21
  type FlowPreviewResult = ReturnType<typeof FlowPreviewResult>;
@@ -3,7 +3,7 @@ import FlowStatusViewerInner from './FlowStatusViewerInner.svelte';
3
3
  import { createEventDispatcher, setContext, untrack } from 'svelte';
4
4
  import { isOwner as loadIsOwner } from '../utils';
5
5
  import { userStore, workspaceStore } from '../stores';
6
- let { jobId, initialJob = undefined, workspaceId = undefined, flowStateStore = writable({}), selectedJobStep = $bindable(undefined), hideFlowResult = false, hideTimeline = false, hideDownloadInGraph = false, hideNodeDefinition = false, hideJobId = false, hideDownloadLogs = false, rightColumnSelect = $bindable('timeline'), isOwner = $bindable(false), wideResults = false, localModuleStates = $bindable(writable({})), localDurationStatuses = $bindable(writable({})), job = $bindable(undefined), render = true, suspendStatus = $bindable(writable({})) } = $props();
6
+ let { jobId, initialJob = undefined, workspaceId = undefined, flowStateStore = writable({}), selectedJobStep = $bindable(undefined), hideFlowResult = false, hideTimeline = false, hideDownloadInGraph = false, hideNodeDefinition = false, hideJobId = false, hideDownloadLogs = false, rightColumnSelect = $bindable('timeline'), isOwner = $bindable(false), wideResults = false, localModuleStates = $bindable(writable({})), localDurationStatuses = $bindable(writable({})), job = $bindable(undefined), render = true, suspendStatus = $bindable(writable({})), customUi } = $props();
7
7
  let lastJobId = jobId;
8
8
  let retryStatus = writable({});
9
9
  setContext('FlowStatusViewer', {
@@ -61,4 +61,5 @@ $effect.pre(() => {
61
61
  {wideResults}
62
62
  bind:rightColumnSelect
63
63
  {render}
64
+ {customUi}
64
65
  />
@@ -22,6 +22,9 @@ interface Props {
22
22
  job?: Job | undefined;
23
23
  render?: boolean;
24
24
  suspendStatus?: any;
25
+ customUi?: {
26
+ tagLabel?: string | undefined;
27
+ };
25
28
  }
26
29
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
27
30
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -27,7 +27,13 @@ import { createState } from '../svelte5Utils.svelte';
27
27
  import JobLoader from './JobLoader.svelte';
28
28
  const dispatch = createEventDispatcher();
29
29
  let { flowStateStore, retryStatus, suspendStatus, hideDownloadInGraph, hideTimeline, hideNodeDefinition, hideDownloadLogs, hideJobId } = getContext('FlowStatusViewer');
30
- let { jobId, initialJob = undefined, workspaceId = undefined, flowJobIds = undefined, innerModule = undefined, globalRefreshes = $bindable({}), render = true, isOwner = false, selectedNode = $bindable(undefined), globalModuleStates, globalDurationStatuses, childFlow = false, isSubflow = false, reducedPolling = false, wideResults = false, hideFlowResult = false, workspace = $workspaceStore, prefix = undefined, subflowParentsGlobalModuleStates = [], subflowParentsDurationStatuses = [], isForloopSelected = false, parentRecursiveRefresh = $bindable({}), job = $bindable(undefined), rightColumnSelect = $bindable('timeline'), localModuleStates = writable({}), localDurationStatuses = writable({}) } = $props();
30
+ let { jobId, initialJob = undefined, workspaceId = undefined, flowJobIds = undefined, innerModule = undefined, globalRefreshes = $bindable({}), render = true, isOwner = false, selectedNode = $bindable(undefined), globalModuleStates, globalDurationStatuses, childFlow = false, isSubflow = false, reducedPolling = false, wideResults = false, hideFlowResult = false, workspace = $workspaceStore, prefix = undefined, subflowParentsGlobalModuleStates = [], subflowParentsDurationStatuses = [], isForloopSelected = false, parentRecursiveRefresh = $bindable({}), job = $bindable(undefined), rightColumnSelect = $bindable('timeline'), localModuleStates = writable({}), localDurationStatuses = writable({}), customUi, onResultStreamUpdate = undefined } = $props();
31
+ let resultStreams = $state({});
32
+ if (onResultStreamUpdate == undefined) {
33
+ onResultStreamUpdate = ({ jobId, result_stream }) => {
34
+ resultStreams[jobId] = result_stream;
35
+ };
36
+ }
31
37
  let recursiveRefresh = $state({});
32
38
  // Add support for the input args assets shown as an asset node
33
39
  const _flowGraphAssetsCtx = getContext('FlowGraphAssetContext');
@@ -76,7 +82,9 @@ function updateModuleStates(moduleState, key, newValue, keepType) {
76
82
  if (newValue.selectedForloop != undefined &&
77
83
  state[key]?.selectedForloop != undefined &&
78
84
  newValue.selectedForloop != state[key].selectedForloop) {
79
- if (newValue.type == 'InProgress' && state[key]?.type != 'InProgress') {
85
+ if (newValue.type == 'InProgress' &&
86
+ state[key]?.type != 'InProgress' &&
87
+ !(keepType && (state[key]?.type === 'Success' || state[key]?.type === 'Failure'))) {
80
88
  moduleState.update((state) => {
81
89
  state[key].type = 'InProgress';
82
90
  return state;
@@ -357,6 +365,9 @@ async function loadJobInProgress() {
357
365
  jobLoader?.watchJob(jobId, {
358
366
  change(newJob) {
359
367
  setJob(newJob, true);
368
+ },
369
+ resultStreamUpdate({ id, result_stream }) {
370
+ onResultStreamUpdate?.({ jobId: id, result_stream });
360
371
  }
361
372
  });
362
373
  }
@@ -685,7 +696,7 @@ $effect(() => {
685
696
  let selected = $derived(isListJob ? 'sequence' : 'graph');
686
697
  </script>
687
698
 
688
- <JobLoader noCode noLogs bind:this={jobLoader} />
699
+ <JobLoader workspaceOverride={workspaceId} noCode noLogs bind:this={jobLoader} />
689
700
  {#if notAnonynmous}
690
701
  <Alert type="error" title="Required Auth">
691
702
  As a non logged in user, you can only see jobs ran by anonymous users like you
@@ -728,6 +739,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
728
739
  <DisplayResult
729
740
  workspaceId={job?.workspace_id}
730
741
  {jobId}
742
+ result_stream={job?.result_stream}
731
743
  result={jobResults}
732
744
  language={job?.language}
733
745
  />
@@ -745,6 +757,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
745
757
  {innerModules}
746
758
  {suspendStatus}
747
759
  {hideJobId}
760
+ result_streams={resultStreams}
748
761
  />
749
762
  </div>
750
763
  {/if}
@@ -836,6 +849,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
836
849
  storedListJobs[j] = job
837
850
  innerJobLoaded(job, j, false, force)
838
851
  }}
852
+ {onResultStreamUpdate}
839
853
  />
840
854
  </div>
841
855
  {/if}
@@ -911,6 +925,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
911
925
  {reducedPolling}
912
926
  {workspaceId}
913
927
  jobId={failedRetry}
928
+ {onResultStreamUpdate}
914
929
  />
915
930
  </div>
916
931
  {/each}
@@ -943,6 +958,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
943
958
  let { force, job } = e.detail
944
959
  onJobsLoaded(mod, job, force)
945
960
  }}
961
+ {onResultStreamUpdate}
946
962
  />
947
963
  {:else if mod.flow_jobs?.length == 0 && mod.job == '00000000-0000-0000-0000-000000000000'}
948
964
  <div class="text-secondary">no subflow (empty loop?)</div>
@@ -974,6 +990,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
974
990
  let { job, force } = e.detail
975
991
  onJobsLoaded(mod, job, force)
976
992
  }}
993
+ {onResultStreamUpdate}
977
994
  />
978
995
  {/if}
979
996
  {:else}
@@ -1113,6 +1130,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
1113
1130
 
1114
1131
  {#if selectedNode == 'end'}
1115
1132
  <FlowJobResult
1133
+ tagLabel={customUi?.tagLabel}
1116
1134
  workspaceId={job?.workspace_id}
1117
1135
  jobId={job?.id}
1118
1136
  filename={job.id}
@@ -1188,6 +1206,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
1188
1206
  </div>
1189
1207
  {/if}
1190
1208
  <FlowJobResult
1209
+ tagLabel={customUi?.tagLabel}
1191
1210
  workspaceId={job?.workspace_id}
1192
1211
  jobId={node.job_id}
1193
1212
  noBorder
@@ -1195,6 +1214,7 @@ let selected = $derived(isListJob ? 'sequence' : 'graph');
1195
1214
  waitingForExecutor={node.type == 'WaitingForExecutor'}
1196
1215
  refreshLog={node.type == 'InProgress'}
1197
1216
  col
1217
+ result_stream={resultStreams[node.job_id ?? '']}
1198
1218
  result={node.result}
1199
1219
  tag={node.tag}
1200
1220
  logs={node.logs}
@@ -31,10 +31,19 @@ interface Props {
31
31
  subflowParentsDurationStatuses?: Writable<Record<string, DurationStatus>>[];
32
32
  isForloopSelected?: boolean;
33
33
  parentRecursiveRefresh?: Record<string, (clear: any, root: any) => Promise<void>>;
34
- job?: Job | undefined;
34
+ job?: (Job & {
35
+ result_stream?: string;
36
+ }) | undefined;
35
37
  rightColumnSelect?: 'timeline' | 'node_status' | 'node_definition' | 'user_states';
36
38
  localModuleStates?: Writable<Record<string, GraphModuleState>>;
37
39
  localDurationStatuses?: Writable<Record<string, DurationStatus>>;
40
+ onResultStreamUpdate?: ({ jobId, result_stream }: {
41
+ jobId: string;
42
+ result_stream?: string;
43
+ }) => void;
44
+ customUi?: {
45
+ tagLabel?: string | undefined;
46
+ };
38
47
  }
39
48
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
40
49
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -250,7 +250,7 @@ run(() => {
250
250
  <div>
251
251
  <ToggleButtonGroup
252
252
  disabled={owner_name == 'u/' + $userStore?.username &&
253
- !$userStore?.is_admin}
253
+ !($userStore?.is_admin || $userStore?.is_super_admin)}
254
254
  selected={role}
255
255
  on:selected={async (e) => {
256
256
  const role = e.detail