windmill-components 1.687.0 → 1.695.1

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 (264) hide show
  1. package/package/components/ArgInput.svelte +2 -0
  2. package/package/components/AutoscalingConfigEditor.svelte +18 -4
  3. package/package/components/CompareWorkspaces.svelte +206 -157
  4. package/package/components/DatatableSchemaDiff.svelte +2 -2
  5. package/package/components/Dev.svelte +401 -85
  6. package/package/components/EditableSchemaForm.svelte +4 -0
  7. package/package/components/ErrorOrRecoveryHandler.svelte +2 -2
  8. package/package/components/FlowPreviewContent.svelte +32 -30
  9. package/package/components/FlowRestartButton.svelte +143 -61
  10. package/package/components/FlowRestartButton.svelte.d.ts +37 -0
  11. package/package/components/FlowStatusViewer.svelte +15 -1
  12. package/package/components/FlowStatusViewer.svelte.d.ts +10 -2
  13. package/package/components/FlowStatusViewerInner.svelte +1 -2
  14. package/package/components/FlowStatusViewerInner.svelte.d.ts +6 -2
  15. package/package/components/ForkConflictModal.svelte +57 -0
  16. package/package/components/ForkConflictModal.svelte.d.ts +3 -0
  17. package/package/components/GitRepoViewer.svelte +251 -97
  18. package/package/components/InputTransformSchemaForm.svelte +1 -1
  19. package/package/components/InstanceSettings.svelte +36 -16
  20. package/package/components/Login.svelte +113 -28
  21. package/package/components/Login.svelte.d.ts +1 -0
  22. package/package/components/Path.svelte +7 -1
  23. package/package/components/Path.svelte.d.ts +1 -1
  24. package/package/components/RunsPage.svelte +2 -1
  25. package/package/components/S3FilePickerInner.svelte +89 -89
  26. package/package/components/ScriptEditor.svelte +18 -5
  27. package/package/components/ShareModal.svelte.d.ts +1 -1
  28. package/package/components/apps/components/helpers/RunnableComponent.svelte.d.ts +3 -0
  29. package/package/components/apps/components/helpers/executeRunnable.js +2 -1
  30. package/package/components/apps/editor/AppReportsDrawerInner.svelte +1 -1
  31. package/package/components/apps/editor/appPolicy.js +2 -1
  32. package/package/components/apps/editor/commonAppUtils.d.ts +3 -0
  33. package/package/components/apps/editor/inlineScriptsPanel/CacheTtlPopup.svelte +1 -1
  34. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte +7 -0
  35. package/package/components/apps/editor/inlineScriptsPanel/TagPopup.svelte +49 -0
  36. package/package/components/apps/editor/inlineScriptsPanel/TagPopup.svelte.d.ts +9 -0
  37. package/package/components/apps/inputType.d.ts +1 -0
  38. package/package/components/apps/sharedTypes.d.ts +1 -0
  39. package/package/components/auditLogs/AuditLogsFilters.svelte +8 -3
  40. package/package/components/common/fileUpload/S3ArgInput.svelte +12 -10
  41. package/package/components/common/fileUpload/S3ArgInput.svelte.d.ts +2 -0
  42. package/package/components/copilot/chat/AIChatDisplay.svelte +5 -36
  43. package/package/components/copilot/chat/AIChatInput.svelte +56 -47
  44. package/package/components/copilot/chat/AIChatManager.svelte.js +48 -46
  45. package/package/components/copilot/chat/ContextElementBadge.svelte +6 -4
  46. package/package/components/copilot/chat/app/core.d.ts +12 -20
  47. package/package/components/copilot/chat/app/core.js +103 -160
  48. package/package/components/copilot/chat/app/core.test.js +234 -9
  49. package/package/components/copilot/chat/context.js +44 -0
  50. package/package/components/copilot/chat/flow/FlowAIChat.svelte +5 -3
  51. package/package/components/copilot/chat/flow/core.d.ts +2 -1
  52. package/package/components/copilot/chat/flow/core.js +48 -21
  53. package/package/components/copilot/chat/flow/helperUtils.d.ts +5 -2
  54. package/package/components/copilot/chat/flow/helperUtils.js +33 -1
  55. package/package/components/copilot/chat/flow/helperUtils.test.js +116 -1
  56. package/package/components/copilot/chat/flow/openFlow.json +1 -1
  57. package/package/components/copilot/chat/flow/openFlowZod.gen.js +24 -0
  58. package/package/components/copilot/chat/script/core.js +3 -0
  59. package/package/components/copilot/chat/shared.d.ts +6 -0
  60. package/package/components/copilot/chat/shared.js +22 -1
  61. package/package/components/copilot/chat/shared.test.d.ts +1 -0
  62. package/package/components/copilot/chat/shared.test.js +412 -0
  63. package/package/components/copilot/chat/workspaceTools.d.ts +7 -0
  64. package/package/components/copilot/chat/workspaceTools.js +239 -0
  65. package/package/components/copilot/chat/workspaceToolsZod.gen.d.ts +1295 -0
  66. package/package/components/copilot/chat/workspaceToolsZod.gen.js +424 -0
  67. package/package/components/copilot/lib.js +3 -1
  68. package/package/components/copilot/lib.test.d.ts +1 -0
  69. package/package/components/copilot/lib.test.js +19 -0
  70. package/package/components/copilot/modelConfig.d.ts +3 -0
  71. package/package/components/copilot/modelConfig.js +10 -0
  72. package/package/components/flows/FlowProgressBar.svelte +5 -2
  73. package/package/components/flows/content/FlowModuleComponent.svelte +636 -599
  74. package/package/components/flows/conversations/FlowChatManager.svelte.js +21 -10
  75. package/package/components/flows/flowStateUtils.svelte.js +5 -1
  76. package/package/components/flows/map/FlowModuleSchemaMap.svelte +3 -2
  77. package/package/components/flows/map/FlowModuleSchemaMap.svelte.d.ts +1 -0
  78. package/package/components/git_sync/GitSyncContext.svelte.js +0 -2
  79. package/package/components/graph/FlowGraphV2.svelte +7 -3
  80. package/package/components/graph/FlowGraphV2.svelte.d.ts +1 -0
  81. package/package/components/graph/renderers/triggers/TriggersBadge.svelte +3 -0
  82. package/package/components/home/deploy_ui.js +1 -1
  83. package/package/components/icons/AzureIcon.svelte +12 -25
  84. package/package/components/icons/AzureIcon.svelte.d.ts +3 -2
  85. package/package/components/instanceSettings.js +24 -0
  86. package/package/components/mcp/McpScopeSelector.svelte +119 -9
  87. package/package/components/mcp/McpScopeSelector.svelte.d.ts +1 -0
  88. package/package/components/offboarding-utils.js +2 -0
  89. package/package/components/progressBar/ProgressBar.svelte +9 -5
  90. package/package/components/progressBar/ProgressBar.svelte.d.ts +1 -0
  91. package/package/components/raw_apps/DeleteAfterUsePopup.svelte +52 -0
  92. package/package/components/raw_apps/DeleteAfterUsePopup.svelte.d.ts +9 -0
  93. package/package/components/raw_apps/RawAppBackgroundRunner.svelte +5 -1
  94. package/package/components/raw_apps/RawAppEditor.svelte +159 -102
  95. package/package/components/raw_apps/RawAppInlineScriptEditor.svelte +9 -3
  96. package/package/components/raw_apps/RawAppInlineScriptEditor.svelte.d.ts +2 -1
  97. package/package/components/raw_apps/RawAppInlineScriptRunnable.svelte +1 -0
  98. package/package/components/raw_apps/RawAppInlineScriptRunnable.svelte.d.ts +1 -0
  99. package/package/components/raw_apps/RawAppInputsSpecEditor.svelte +48 -5
  100. package/package/components/raw_apps/RawAppSharedUiDrawer.svelte +129 -0
  101. package/package/components/raw_apps/RawAppSharedUiDrawer.svelte.d.ts +5 -0
  102. package/package/components/raw_apps/RawAppSidebar.svelte +12 -0
  103. package/package/components/raw_apps/dataTableRefUtils.d.ts +7 -0
  104. package/package/components/raw_apps/dataTableRefUtils.js +34 -0
  105. package/package/components/raw_apps/dataTableRefUtils.test.d.ts +1 -0
  106. package/package/components/raw_apps/dataTableRefUtils.test.js +29 -0
  107. package/package/components/raw_apps/rawAppPolicy.d.ts +1 -0
  108. package/package/components/raw_apps/rawAppPolicy.js +17 -2
  109. package/package/components/resources/resourceTypesFilter.d.ts +19 -0
  110. package/package/components/resources/resourceTypesFilter.js +21 -0
  111. package/package/components/restartFromStepPath.d.ts +39 -0
  112. package/package/components/restartFromStepPath.js +89 -0
  113. package/package/components/runs/JobDetailFieldConfig.d.ts +1 -0
  114. package/package/components/runs/JobDetailFieldConfig.js +57 -10
  115. package/package/components/runs/JobDetailHeader.svelte +24 -3
  116. package/package/components/runs/runsFilter.d.ts +1 -1
  117. package/package/components/schema/FlowPropertyEditor.svelte +30 -1
  118. package/package/components/schema/FlowPropertyEditor.svelte.d.ts +5 -2
  119. package/package/components/search/GlobalSearchModal.svelte +8 -1
  120. package/package/components/select/Select.svelte +1 -1
  121. package/package/components/settings/CreateToken.svelte +48 -77
  122. package/package/components/settings/EditTokenScopesModal.svelte +57 -0
  123. package/package/components/settings/EditTokenScopesModal.svelte.d.ts +10 -0
  124. package/package/components/settings/ScopesPicker.svelte +43 -0
  125. package/package/components/settings/ScopesPicker.svelte.d.ts +11 -0
  126. package/package/components/settings/TokensTable.svelte +51 -15
  127. package/package/components/sidebar/OperatorMenu.svelte +6 -0
  128. package/package/components/sidebar/SidebarContent.svelte +11 -1
  129. package/package/components/triggers/AddTriggersButton.svelte +6 -0
  130. package/package/components/triggers/CaptureWrapper.svelte +19 -1
  131. package/package/components/triggers/TriggerEditorToolbar.svelte.d.ts +1 -1
  132. package/package/components/triggers/TriggerModeToggle.svelte +36 -7
  133. package/package/components/triggers/TriggerModeToggle.svelte.d.ts +1 -1
  134. package/package/components/triggers/TriggerSuspendedJobsModal.svelte.d.ts +1 -1
  135. package/package/components/triggers/TriggersEditor.svelte +5 -1
  136. package/package/components/triggers/TriggersWrapper.svelte +10 -0
  137. package/package/components/triggers/azure/AzureCapture.svelte +41 -0
  138. package/package/components/triggers/azure/AzureCapture.svelte.d.ts +44 -0
  139. package/package/components/triggers/azure/AzureTriggerEditor.svelte +20 -0
  140. package/package/components/triggers/azure/AzureTriggerEditor.svelte.d.ts +9 -0
  141. package/package/components/triggers/azure/AzureTriggerEditorConfigSection.svelte +301 -0
  142. package/package/components/triggers/azure/AzureTriggerEditorConfigSection.svelte.d.ts +16 -0
  143. package/package/components/triggers/azure/AzureTriggerEditorInner.svelte +422 -0
  144. package/package/components/triggers/azure/AzureTriggerEditorInner.svelte.d.ts +25 -0
  145. package/package/components/triggers/azure/AzureTriggerPanel.svelte +55 -0
  146. package/package/components/triggers/azure/AzureTriggerPanel.svelte.d.ts +10 -0
  147. package/{dist/sharedUtils/components/triggers/kafka → package/components/triggers/azure}/utils.d.ts +1 -1
  148. package/package/components/triggers/azure/utils.js +56 -0
  149. package/package/components/triggers/email/EmailTriggerEditorInner.svelte +2 -0
  150. package/package/components/triggers/gcp/GcpTriggerEditorInner.svelte +9 -3
  151. package/package/components/triggers/http/RouteEditorInner.svelte +2 -0
  152. package/package/components/triggers/kafka/KafkaTriggerEditorInner.svelte +9 -3
  153. package/package/components/triggers/mqtt/MqttTriggerEditorInner.svelte +9 -3
  154. package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +9 -3
  155. package/package/components/triggers/postgres/PostgresTriggerEditorInner.svelte +9 -3
  156. package/package/components/triggers/schedules/ScheduleEditorInner.svelte +9 -3
  157. package/package/components/triggers/sqs/SqsTriggerEditorInner.svelte +9 -3
  158. package/package/components/triggers/triggers.svelte.d.ts +1 -0
  159. package/package/components/triggers/triggers.svelte.js +23 -1
  160. package/package/components/triggers/utils.js +20 -0
  161. package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +9 -3
  162. package/package/components/triggers.d.ts +1 -1
  163. package/package/components/useNestedRestartState.svelte.d.ts +56 -0
  164. package/package/components/useNestedRestartState.svelte.js +320 -0
  165. package/package/components/workspaceSettings/SharedUiSettings.svelte +175 -0
  166. package/package/components/workspaceSettings/SharedUiSettings.svelte.d.ts +3 -0
  167. package/package/gen/core/OpenAPI.js +1 -1
  168. package/package/gen/schemas.gen.d.ts +294 -24
  169. package/package/gen/schemas.gen.js +297 -25
  170. package/package/gen/services.gen.d.ts +247 -4
  171. package/package/gen/services.gen.js +498 -7
  172. package/package/gen/types.gen.d.ts +990 -37
  173. package/package/hubPaths.json +2 -5
  174. package/package/infer.d.ts +1 -1
  175. package/package/infer.js +37 -51
  176. package/package/mcpEndpointTools.js +60 -4
  177. package/package/script_helpers.js +17 -0
  178. package/package/stores.d.ts +7 -0
  179. package/package/stores.js +6 -1
  180. package/package/system_prompts/index.d.ts +1 -0
  181. package/package/system_prompts/index.js +8 -0
  182. package/package/system_prompts/prompts.d.ts +16 -13
  183. package/package/system_prompts/prompts.js +653 -43
  184. package/package/templates/ci_test_bun.ts.template +8 -0
  185. package/package/templates/ci_test_python.py.template +8 -0
  186. package/package/utils/forkConflict.d.ts +26 -0
  187. package/package/utils/forkConflict.js +56 -0
  188. package/package/utils_deployable.d.ts +164 -121
  189. package/package/utils_deployable.js +61 -11
  190. package/package/utils_workspace_deploy.js +3 -1
  191. package/package.json +29 -5
  192. package/dist/sharedUtils/assets/tokens/colorTokensConfig.d.ts +0 -2
  193. package/dist/sharedUtils/base.d.ts +0 -1
  194. package/dist/sharedUtils/cloud.d.ts +0 -1
  195. package/dist/sharedUtils/common.d.ts +0 -111
  196. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/count.d.ts +0 -5
  197. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/delete.d.ts +0 -5
  198. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/insert.d.ts +0 -5
  199. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/select.d.ts +0 -13
  200. package/dist/sharedUtils/components/apps/components/display/dbtable/queries/update.d.ts +0 -11
  201. package/dist/sharedUtils/components/apps/components/display/dbtable/utils.d.ts +0 -95
  202. package/dist/sharedUtils/components/apps/editor/appPolicy.d.ts +0 -6
  203. package/dist/sharedUtils/components/apps/editor/appUtilsCore.d.ts +0 -7
  204. package/dist/sharedUtils/components/apps/editor/appUtilsS3.d.ts +0 -33
  205. package/dist/sharedUtils/components/apps/editor/commonAppUtils.d.ts +0 -10
  206. package/dist/sharedUtils/components/apps/editor/component/components.d.ts +0 -5371
  207. package/dist/sharedUtils/components/apps/editor/component/default-codes.d.ts +0 -3
  208. package/dist/sharedUtils/components/apps/editor/component/index.d.ts +0 -3
  209. package/dist/sharedUtils/components/apps/editor/component/sets.d.ts +0 -7
  210. package/dist/sharedUtils/components/apps/editor/componentsPanel/componentDefaultProps.d.ts +0 -3
  211. package/dist/sharedUtils/components/apps/gridUtils.d.ts +0 -14
  212. package/dist/sharedUtils/components/apps/inputType.d.ts +0 -178
  213. package/dist/sharedUtils/components/apps/rx.d.ts +0 -29
  214. package/dist/sharedUtils/components/apps/sharedTypes.d.ts +0 -21
  215. package/dist/sharedUtils/components/apps/types.d.ts +0 -274
  216. package/dist/sharedUtils/components/assets/lib.d.ts +0 -25
  217. package/dist/sharedUtils/components/common/alert/model.d.ts +0 -2
  218. package/dist/sharedUtils/components/common/badge/model.d.ts +0 -8
  219. package/dist/sharedUtils/components/common/button/model.d.ts +0 -45
  220. package/dist/sharedUtils/components/common/fileInput/model.d.ts +0 -1
  221. package/dist/sharedUtils/components/common/index.d.ts +0 -24
  222. package/dist/sharedUtils/components/common/skeleton/model.d.ts +0 -21
  223. package/dist/sharedUtils/components/dbTypes.d.ts +0 -14
  224. package/dist/sharedUtils/components/diff_drawer.d.ts +0 -26
  225. package/dist/sharedUtils/components/ducklake.d.ts +0 -1
  226. package/dist/sharedUtils/components/flows/scheduleUtils.d.ts +0 -7
  227. package/dist/sharedUtils/components/icons/index.d.ts +0 -101
  228. package/dist/sharedUtils/components/random_positive_adjetive.d.ts +0 -1
  229. package/dist/sharedUtils/components/raw_apps/rawAppPolicy.d.ts +0 -10
  230. package/dist/sharedUtils/components/raw_apps/utils.d.ts +0 -15
  231. package/dist/sharedUtils/components/triggers/email/utils.d.ts +0 -4
  232. package/dist/sharedUtils/components/triggers/gcp/utils.d.ts +0 -2
  233. package/dist/sharedUtils/components/triggers/http/utils.d.ts +0 -11
  234. package/dist/sharedUtils/components/triggers/mqtt/utils.d.ts +0 -2
  235. package/dist/sharedUtils/components/triggers/nats/utils.d.ts +0 -2
  236. package/dist/sharedUtils/components/triggers/postgres/utils.d.ts +0 -8
  237. package/dist/sharedUtils/components/triggers/sqs/utils.d.ts +0 -2
  238. package/dist/sharedUtils/components/triggers/triggers.svelte.d.ts +0 -32
  239. package/dist/sharedUtils/components/triggers/utils.d.ts +0 -80
  240. package/dist/sharedUtils/components/triggers/websocket/utils.d.ts +0 -2
  241. package/dist/sharedUtils/components/triggers.d.ts +0 -20
  242. package/dist/sharedUtils/gen/core/ApiError.d.ts +0 -10
  243. package/dist/sharedUtils/gen/core/ApiRequestOptions.d.ts +0 -13
  244. package/dist/sharedUtils/gen/core/ApiResult.d.ts +0 -7
  245. package/dist/sharedUtils/gen/core/CancelablePromise.d.ts +0 -26
  246. package/dist/sharedUtils/gen/core/OpenAPI.d.ts +0 -27
  247. package/dist/sharedUtils/gen/core/request.d.ts +0 -29
  248. package/dist/sharedUtils/gen/index.d.ts +0 -6
  249. package/dist/sharedUtils/gen/schemas.gen.d.ts +0 -7036
  250. package/dist/sharedUtils/gen/services.gen.d.ts +0 -6047
  251. package/dist/sharedUtils/gen/types.gen.d.ts +0 -21881
  252. package/dist/sharedUtils/history.svelte.d.ts +0 -9
  253. package/dist/sharedUtils/hub.d.ts +0 -49
  254. package/dist/sharedUtils/jsr.json +0 -6
  255. package/dist/sharedUtils/lib.d.ts +0 -5
  256. package/dist/sharedUtils/lib.es.js +0 -1588
  257. package/dist/sharedUtils/package.json +0 -12
  258. package/dist/sharedUtils/schema.d.ts +0 -3
  259. package/dist/sharedUtils/stores.d.ts +0 -97
  260. package/dist/sharedUtils/svelte5Utils.svelte.d.ts +0 -80
  261. package/dist/sharedUtils/toast.d.ts +0 -8
  262. package/dist/sharedUtils/utils.d.ts +0 -265
  263. package/package/components/copilot/chat/flow/openFlowZod.js +0 -24
  264. /package/package/components/copilot/chat/flow/{openFlowZod.d.ts → openFlowZod.gen.d.ts} +0 -0
@@ -0,0 +1,320 @@
1
+ import { findStepPath, parseExpandedSubflowId } from './restartFromStepPath';
2
+ import { emptyString } from '../utils';
3
+ /**
4
+ * Returns true when the BranchOne ancestor's path branch (the one containing the
5
+ * selected leaf, encoded as `branchIndex` where -1 means default and 0..N-1
6
+ * means `branches[i]`) is the same branch the original run took. If the user
7
+ * clicked a step inside an `else` branch the original run didn't take, the
8
+ * step never executed — restart there is impossible.
9
+ *
10
+ * Three states for the lookup:
11
+ * - `status === undefined`: the BranchOne isn't at the parent's top level, so
12
+ * it lives on a child job we don't fetch here (e.g. nested inside a ForLoop
13
+ * iteration). Permissive fallback — let the backend reject if needed.
14
+ * - `status` defined but `chosen === undefined`: the BranchOne IS at the top
15
+ * level but has no chosen branch (never executed / skipped / still
16
+ * waiting). The leaf can't have run either, so reject.
17
+ * - both defined: compare against `branchIndex`.
18
+ */
19
+ function branchOneAncestorMatchesOriginal(job, ancestor) {
20
+ if (ancestor.type !== 'branchone')
21
+ return true;
22
+ const status = job.flow_status?.modules?.find((m) => m.id === ancestor.stepId);
23
+ const chosen = status?.branch_chosen;
24
+ if (!chosen)
25
+ return status === undefined;
26
+ const taken = chosen.type === 'default' ? -1 : (chosen.branch ?? -1);
27
+ return ancestor.branchIndex === taken;
28
+ }
29
+ /**
30
+ * Reactive state shared by the run page and the editor's flow preview to drive
31
+ * the "restart flow at step" UI. Given the currently selected step, the
32
+ * completed flow job, the graph's per-module display state, and any expanded
33
+ * subflow definitions, derives:
34
+ *
35
+ * - `selectedJobStepIsTopLevel` — whether the selected step appears in the
36
+ * parent flow's top-level `flow_status.modules`
37
+ * - `selectedJobStepType` — `single` / `forloop` / `branchall`, used by the
38
+ * popup to decide which controls to render for the OUTER container
39
+ * - `restartBranchNames` — for top-level BranchAll steps, the labels for the
40
+ * branch picker
41
+ * - `nestedRestartTopStepId` / `nestedRestartTopBranchOrIterationN` /
42
+ * `nestedRestartPath` — the API request shape when restarting at a nested
43
+ * step (single source of truth for both call sites)
44
+ * - `nestedRestartSupported` — gate for showing the button when the selected
45
+ * step is nested (subflow expansion or BranchOne / sequential ForLoop)
46
+ * - `topLevelLoopIteration` — when the selected step IS a top-level ForLoop,
47
+ * the iteration the user is currently viewing (pre-fills the popup input)
48
+ * - `iterationCounts` — map of step id → number of recorded iterations,
49
+ * so the popup can render an iteration `<select>` matching the graph's tabs
50
+ * instead of a free-form number input
51
+ *
52
+ * Inputs are passed as getters so the composable stays reactive in either
53
+ * caller's signal graph.
54
+ */
55
+ export function useNestedRestartState(opts) {
56
+ let selectedJobStepIsTopLevel = $state(undefined);
57
+ let selectedJobStepType = $state('single');
58
+ let restartBranchNames = $state([]);
59
+ let nestedRestartTopStepId = $state(undefined);
60
+ let nestedRestartTopBranchOrIterationN = $state(undefined);
61
+ let nestedRestartPath = $state(undefined);
62
+ let nestedRestartSupported = $state(false);
63
+ // Iteration counts keyed by the popup's field-key ('top' or 'inner-N').
64
+ // Built during path construction so each entry uses the *correct* graph key
65
+ // for its level (prefixed for in-subflow ancestors). Avoids the collision
66
+ // that would happen if we double-indexed `iterationCounts` by bare step_id.
67
+ let nestedPathIterationCounts = $state({});
68
+ $effect(() => {
69
+ const selectedJobStep = opts.selectedJobStep();
70
+ const job = opts.job();
71
+ const graphModuleStates = opts.graphModuleStates();
72
+ const expandedSubflows = opts.expandedSubflows?.() ?? {};
73
+ nestedRestartTopStepId = undefined;
74
+ nestedRestartTopBranchOrIterationN = undefined;
75
+ nestedRestartPath = undefined;
76
+ nestedRestartSupported = false;
77
+ restartBranchNames = [];
78
+ selectedJobStepIsTopLevel = undefined;
79
+ nestedPathIterationCounts = {};
80
+ if (selectedJobStep === undefined || job?.flow_status?.modules === undefined) {
81
+ return;
82
+ }
83
+ const isTopLevel = job.flow_status.modules.findIndex((m) => m.id === selectedJobStep) >= 0;
84
+ selectedJobStepIsTopLevel = isTopLevel;
85
+ const moduleDefinition = job.raw_flow?.modules.find((m) => m.id === selectedJobStep);
86
+ if (moduleDefinition?.value.type === 'forloopflow') {
87
+ selectedJobStepType = 'forloop';
88
+ }
89
+ else if (moduleDefinition?.value.type === 'branchall') {
90
+ selectedJobStepType = 'branchall';
91
+ const newNames = [];
92
+ moduleDefinition.value.branches.forEach((branch, idx) => {
93
+ newNames.push([idx, emptyString(branch.summary) ? `Branch #${idx}` : branch.summary]);
94
+ });
95
+ restartBranchNames = newNames;
96
+ }
97
+ else {
98
+ selectedJobStepType = 'single';
99
+ }
100
+ // Read from the local — reading the `$state` we just wrote would register
101
+ // it as a dependency of this effect, causing `effect_update_depth_exceeded`
102
+ // because each write would reschedule the effect.
103
+ if (isTopLevel)
104
+ return;
105
+ // Inline-expanded subflow: id is `subflow:outerStep:[innerSubflow:...]<leaf>`.
106
+ // The graph adds the `subflow:` prefix only for subflow expansions, so each
107
+ // segment is a `Flow{path}` step. We walk the chain and, at the deepest
108
+ // subflow, recurse into its cached modules to detect BranchOne / ForLoop
109
+ // ancestors of the leaf so the chain captures locked branches and
110
+ // iteration indices for those too.
111
+ const subflowParse = parseExpandedSubflowId(selectedJobStep);
112
+ if (subflowParse && job.raw_flow?.modules) {
113
+ const top = job.raw_flow.modules.find((m) => m.id === subflowParse.subflowSteps[0]);
114
+ if (top && top.value.type === 'flow') {
115
+ const innerPath = [];
116
+ // Intermediate subflow boundaries: each is itself a Flow{path}, no
117
+ // branch_or_iteration_n applies.
118
+ for (const seg of subflowParse.subflowSteps.slice(1)) {
119
+ innerPath.push({ step_id: seg });
120
+ }
121
+ // Look up the deepest subflow's modules in expandedSubflows. The graph
122
+ // stores them under the prefixed key (the graph node id used at that
123
+ // nesting level).
124
+ const deepestKey = subflowParse.subflowSteps.length === 1
125
+ ? subflowParse.subflowSteps[0]
126
+ : 'subflow:' + subflowParse.subflowSteps.join(':');
127
+ const deepestModules = expandedSubflows[deepestKey]?.modules;
128
+ if (deepestModules) {
129
+ const path = findStepPath(deepestModules, subflowParse.leaf);
130
+ if (path) {
131
+ // Same gating as the parent-flow case, minus the BranchOne
132
+ // branch-mismatch check (subflow's flow_status isn't directly
133
+ // reachable here; backend will still reject if the branch
134
+ // wasn't taken). Parallel and unsupported containers are checked.
135
+ const blocked = path.ancestors.some((a) => a.type === 'branchall' || a.type === 'whileloopflow' || a.parallel === true);
136
+ if (!blocked) {
137
+ // Inside the subflow, the graph state for ForLoop ancestors
138
+ // is keyed by the prefixed graph id. Build that key here so
139
+ // `selectedForloopIndex` and `flow_jobs.length` lookups land
140
+ // on the right entry (avoiding collisions with same-step-id
141
+ // loops in the parent flow — e.g. parent has `e` with 4 iters
142
+ // and the subflow also has `e` with 1 iter).
143
+ const subflowPrefix = 'subflow:' + subflowParse.subflowSteps.join(':') + ':';
144
+ const iterationFor = (stepId) => graphModuleStates[subflowPrefix + stepId]?.selectedForloopIndex ?? 0;
145
+ const iterCountFor = (stepId) => graphModuleStates[subflowPrefix + stepId]?.flow_jobs?.length ?? 0;
146
+ const counts = {};
147
+ // Top-level (parent) container is the subflow step `h` —
148
+ // not a ForLoop, no count.
149
+ for (let i = 0; i < path.ancestors.length; i++) {
150
+ const a = path.ancestors[i];
151
+ const entry = { step_id: a.stepId };
152
+ if (a.type === 'forloopflow') {
153
+ entry.branch_or_iteration_n = iterationFor(a.stepId);
154
+ // Path key: each subflow boundary already contributes an
155
+ // inner-N entry above (subflow steps without iterations).
156
+ // Match the index that FlowRestartButton will use when
157
+ // rendering iteration fields.
158
+ counts[`inner-${innerPath.length}`] = iterCountFor(a.stepId);
159
+ }
160
+ innerPath.push(entry);
161
+ }
162
+ const leafEntry = { step_id: subflowParse.leaf };
163
+ if (path.target.value.type === 'forloopflow') {
164
+ leafEntry.branch_or_iteration_n = iterationFor(subflowParse.leaf);
165
+ counts[`inner-${innerPath.length}`] = iterCountFor(subflowParse.leaf);
166
+ }
167
+ innerPath.push(leafEntry);
168
+ nestedRestartTopStepId = top.id;
169
+ nestedRestartPath = innerPath;
170
+ nestedPathIterationCounts = counts;
171
+ nestedRestartSupported = true;
172
+ return;
173
+ }
174
+ }
175
+ }
176
+ // Fallback: subflow's modules not yet loaded (user clicked a step
177
+ // without expanding the subflow first), or leaf not found / blocked.
178
+ // Send a flat path; the backend will reject if the leaf is nested
179
+ // inside an unsupported container.
180
+ innerPath.push({ step_id: subflowParse.leaf });
181
+ nestedRestartTopStepId = top.id;
182
+ nestedRestartPath = innerPath;
183
+ nestedRestartSupported = true;
184
+ return;
185
+ }
186
+ }
187
+ // BranchOne / sequential ForLoop within the parent's own flow_value. Walk
188
+ // the tree to find the path; supported when ancestors are BranchOne /
189
+ // sequential ForLoop only — and only when each BranchOne ancestor's chosen
190
+ // branch in the original run actually contains the leaf, otherwise the
191
+ // step never executed and the backend would error.
192
+ if (!job.raw_flow?.modules)
193
+ return;
194
+ const path = findStepPath(job.raw_flow.modules, selectedJobStep);
195
+ if (!path || path.ancestors.length === 0)
196
+ return;
197
+ const blocked = path.ancestors.some((a) => a.type === 'branchall' ||
198
+ a.type === 'whileloopflow' ||
199
+ a.parallel === true ||
200
+ (a.type === 'branchone' && !branchOneAncestorMatchesOriginal(job, a)));
201
+ if (blocked)
202
+ return;
203
+ // For each ForLoop ancestor, default to the user's currently-open iteration
204
+ // (`selectedForloopIndex`); fall back to 0. The popup surfaces every value
205
+ // for confirmation/editing before submit, so we never silently send a guess.
206
+ const iterationFor = (stepId) => graphModuleStates[stepId]?.selectedForloopIndex ?? 0;
207
+ const iterCountFor = (stepId) => graphModuleStates[stepId]?.flow_jobs?.length ?? 0;
208
+ const top = path.ancestors[0];
209
+ const inner = path.ancestors.slice(1);
210
+ const innerPath = [];
211
+ const counts = {};
212
+ for (const a of inner) {
213
+ const entry = { step_id: a.stepId };
214
+ if (a.type === 'forloopflow') {
215
+ entry.branch_or_iteration_n = iterationFor(a.stepId);
216
+ counts[`inner-${innerPath.length}`] = iterCountFor(a.stepId);
217
+ }
218
+ innerPath.push(entry);
219
+ }
220
+ // If the SELECTED step is itself a ForLoop, include its iteration too so
221
+ // the popup exposes a selector for it.
222
+ const leafEntry = { step_id: selectedJobStep };
223
+ if (path.target.value.type === 'forloopflow') {
224
+ leafEntry.branch_or_iteration_n = iterationFor(selectedJobStep);
225
+ counts[`inner-${innerPath.length}`] = iterCountFor(selectedJobStep);
226
+ }
227
+ innerPath.push(leafEntry);
228
+ nestedRestartTopStepId = top.stepId;
229
+ if (top.type === 'forloopflow') {
230
+ nestedRestartTopBranchOrIterationN = iterationFor(top.stepId);
231
+ counts['top'] = iterCountFor(top.stepId);
232
+ }
233
+ nestedRestartPath = innerPath;
234
+ nestedPathIterationCounts = counts;
235
+ nestedRestartSupported = true;
236
+ });
237
+ const topLevelLoopIteration = $derived.by(() => {
238
+ const sel = opts.selectedJobStep();
239
+ if (!sel)
240
+ return undefined;
241
+ if (selectedJobStepType !== 'forloop')
242
+ return undefined;
243
+ return opts.graphModuleStates()[sel]?.selectedForloopIndex;
244
+ });
245
+ // `selectedJobStepIsTopLevel` answers "is this a top-level module structurally";
246
+ // `topLevelRestartable` answers "AND should the restart button show". The
247
+ // difference: parallel ForLoop / parallel BranchAll at the top level are
248
+ // rejected by the backend, so we hide the button preemptively.
249
+ const topLevelRestartable = $derived.by(() => {
250
+ if (!selectedJobStepIsTopLevel)
251
+ return false;
252
+ const sel = opts.selectedJobStep();
253
+ const job = opts.job();
254
+ if (!sel || !job?.raw_flow?.modules)
255
+ return false;
256
+ const mod = job.raw_flow.modules.find((m) => m.id === sel);
257
+ if (!mod)
258
+ return false;
259
+ const v = mod.value;
260
+ if ((v.type === 'forloopflow' || v.type === 'branchall' || v.type === 'whileloopflow') &&
261
+ v.parallel === true) {
262
+ return false;
263
+ }
264
+ return true;
265
+ });
266
+ // Iteration counts indexed by the graph module-state key (i.e. the prefixed
267
+ // `subflow:...:<step_id>` for in-subflow loops, or the bare `step_id` for
268
+ // top-level loops). Used by the popup for the SELECTED step's iteration
269
+ // picker — that step is always at the unprefixed top level (the run page's
270
+ // graph-state key matches the bare step_id), so the lookup is unambiguous.
271
+ // For nested-path iteration fields, see `nestedPathIterationCounts` instead,
272
+ // which is keyed by the popup's field-key ('top' / 'inner-N') and pulled
273
+ // from the path-aware graph key — avoiding collisions when the same step
274
+ // id appears at both the parent flow and inside a subflow.
275
+ const iterationCounts = $derived.by(() => {
276
+ const out = {};
277
+ for (const [id, state] of Object.entries(opts.graphModuleStates())) {
278
+ const n = state.flow_jobs?.length;
279
+ if (typeof n !== 'number' || n <= 0)
280
+ continue;
281
+ out[id] = n;
282
+ }
283
+ return out;
284
+ });
285
+ return {
286
+ get selectedJobStepIsTopLevel() {
287
+ return selectedJobStepIsTopLevel;
288
+ },
289
+ get selectedJobStepType() {
290
+ return selectedJobStepType;
291
+ },
292
+ get restartBranchNames() {
293
+ return restartBranchNames;
294
+ },
295
+ get nestedRestartTopStepId() {
296
+ return nestedRestartTopStepId;
297
+ },
298
+ get nestedRestartTopBranchOrIterationN() {
299
+ return nestedRestartTopBranchOrIterationN;
300
+ },
301
+ get nestedRestartPath() {
302
+ return nestedRestartPath;
303
+ },
304
+ get nestedRestartSupported() {
305
+ return nestedRestartSupported;
306
+ },
307
+ get topLevelLoopIteration() {
308
+ return topLevelLoopIteration;
309
+ },
310
+ get topLevelRestartable() {
311
+ return topLevelRestartable;
312
+ },
313
+ get iterationCounts() {
314
+ return iterationCounts;
315
+ },
316
+ get nestedPathIterationCounts() {
317
+ return nestedPathIterationCounts;
318
+ }
319
+ };
320
+ }
@@ -0,0 +1,175 @@
1
+ <script lang="ts">import { onMount } from 'svelte';
2
+ import JSZip from 'jszip';
3
+ import Button from '../common/button/Button.svelte';
4
+ import { workspaceStore, userStore } from '../../stores';
5
+ import { sendUserToast } from '../../toast';
6
+ import { WorkspaceService } from '../../gen';
7
+ import { Download, Upload, RefreshCw } from 'lucide-svelte';
8
+ let listing = $state(undefined);
9
+ let loading = $state(false);
10
+ let uploading = $state(false);
11
+ let fileInput = $state(undefined);
12
+ const isAdmin = $derived(!!$userStore?.is_admin);
13
+ async function loadListing() {
14
+ if (!$workspaceStore)
15
+ return;
16
+ loading = true;
17
+ try {
18
+ listing = (await WorkspaceService.listSharedUi({
19
+ workspace: $workspaceStore
20
+ }));
21
+ }
22
+ catch (e) {
23
+ sendUserToast(`Failed to load shared UI: ${e}`, true);
24
+ }
25
+ finally {
26
+ loading = false;
27
+ }
28
+ }
29
+ function humanSize(bytes) {
30
+ if (bytes < 1024)
31
+ return `${bytes} B`;
32
+ if (bytes < 1024 * 1024)
33
+ return `${(bytes / 1024).toFixed(1)} KB`;
34
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
35
+ }
36
+ async function downloadZip() {
37
+ if (!$workspaceStore)
38
+ return;
39
+ try {
40
+ const got = await WorkspaceService.getSharedUi({ workspace: $workspaceStore });
41
+ const files = got.files ?? {};
42
+ const zip = new JSZip();
43
+ for (const [path, content] of Object.entries(files)) {
44
+ zip.file(path, content);
45
+ }
46
+ const blob = await zip.generateAsync({ type: 'blob' });
47
+ const url = URL.createObjectURL(blob);
48
+ const a = document.createElement('a');
49
+ a.href = url;
50
+ a.download = `${$workspaceStore}-ui.zip`;
51
+ a.click();
52
+ URL.revokeObjectURL(url);
53
+ }
54
+ catch (e) {
55
+ sendUserToast(`Failed to download shared UI: ${e}`, true);
56
+ }
57
+ }
58
+ async function onFileSelected(event) {
59
+ const target = event.target;
60
+ const file = target.files?.[0];
61
+ if (!file || !$workspaceStore)
62
+ return;
63
+ uploading = true;
64
+ try {
65
+ const zip = await JSZip.loadAsync(await file.arrayBuffer());
66
+ const files = {};
67
+ const tasks = [];
68
+ zip.forEach((relativePath, entry) => {
69
+ if (entry.dir)
70
+ return;
71
+ tasks.push(entry.async('string').then((content) => {
72
+ files[relativePath] = content;
73
+ }));
74
+ });
75
+ await Promise.all(tasks);
76
+ await WorkspaceService.updateSharedUi({
77
+ workspace: $workspaceStore,
78
+ requestBody: { files }
79
+ });
80
+ sendUserToast(`Replaced shared UI folder with ${Object.keys(files).length} file(s)`);
81
+ await loadListing();
82
+ }
83
+ catch (e) {
84
+ sendUserToast(`Failed to replace shared UI: ${e}`, true);
85
+ }
86
+ finally {
87
+ uploading = false;
88
+ if (fileInput) {
89
+ fileInput.value = '';
90
+ }
91
+ }
92
+ }
93
+ onMount(() => {
94
+ loadListing();
95
+ });
96
+ </script>
97
+
98
+ <div class="mb-6">
99
+ <h2 class="text-lg font-semibold mb-1">Shared UI folder</h2>
100
+ <p class="text-sm text-secondary">
101
+ Workspace-shared frontend files (components, styles, helpers) that the raw app bundler merges
102
+ under the <code>/ui/</code> path. Raw apps can import shared components with
103
+ <code>{`import { Button } from '/ui/Button'`}</code>.
104
+ </p>
105
+ <p class="text-sm text-secondary mt-2">
106
+ Editing happens through the Windmill CLI (<code>wmill sync</code> writes/reads the
107
+ <code>ui/</code> folder at the root of your sync directory). This page lets you inspect or
108
+ replace the entire folder. Changes do <strong>not</strong> retroactively rebuild deployed raw apps
109
+ — re-push affected raw apps to pick up updates.
110
+ </p>
111
+ </div>
112
+
113
+ <div class="flex items-center gap-2 mb-4">
114
+ <Button
115
+ size="xs"
116
+ variant="default"
117
+ startIcon={{ icon: RefreshCw }}
118
+ on:click={loadListing}
119
+ disabled={loading}
120
+ >
121
+ Refresh
122
+ </Button>
123
+ <Button
124
+ size="xs"
125
+ variant="default"
126
+ startIcon={{ icon: Download }}
127
+ on:click={downloadZip}
128
+ disabled={!listing || listing.paths.length === 0}
129
+ >
130
+ Download as zip
131
+ </Button>
132
+ {#if isAdmin}
133
+ <Button
134
+ size="xs"
135
+ variant="default"
136
+ startIcon={{ icon: Upload }}
137
+ on:click={() => fileInput?.click()}
138
+ disabled={uploading}
139
+ >
140
+ {uploading ? 'Replacing…' : 'Replace from zip'}
141
+ </Button>
142
+ <input
143
+ bind:this={fileInput}
144
+ type="file"
145
+ accept=".zip"
146
+ style="display: none;"
147
+ onchange={onFileSelected}
148
+ />
149
+ {/if}
150
+ </div>
151
+
152
+ {#if listing}
153
+ <div class="text-xs text-secondary mb-2">
154
+ Version {listing.version}{#if listing.edited_by}
155
+ · Last edited by <code>{listing.edited_by}</code>
156
+ {/if}
157
+ </div>
158
+ {#if listing.paths.length === 0}
159
+ <div class="rounded border border-dashed p-6 text-center text-sm text-secondary">
160
+ The shared UI folder is empty. Create a <code>ui/</code> directory next to your
161
+ <code>f/</code> and <code>u/</code> folders, add files, then run <code>wmill sync push</code>.
162
+ </div>
163
+ {:else}
164
+ <div class="rounded border divide-y">
165
+ {#each listing.paths as p (p)}
166
+ <div class="flex items-center justify-between px-3 py-2 text-sm font-mono">
167
+ <span class="truncate">{p}</span>
168
+ <span class="text-xs text-secondary">{humanSize(listing.sizes[p] ?? 0)}</span>
169
+ </div>
170
+ {/each}
171
+ </div>
172
+ {/if}
173
+ {:else if loading}
174
+ <div class="text-sm text-secondary">Loading…</div>
175
+ {/if}
@@ -0,0 +1,3 @@
1
+ declare const SharedUiSettings: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type SharedUiSettings = ReturnType<typeof SharedUiSettings>;
3
+ export default SharedUiSettings;
@@ -21,7 +21,7 @@ export const OpenAPI = {
21
21
  PASSWORD: undefined,
22
22
  TOKEN: undefined,
23
23
  USERNAME: undefined,
24
- VERSION: '1.687.0',
24
+ VERSION: '1.695.0',
25
25
  WITH_CREDENTIALS: false,
26
26
  interceptors: {
27
27
  request: new Interceptors(),