windmill-components 1.531.1 → 1.537.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 (153) hide show
  1. package/package/components/ArgInput.svelte +69 -19
  2. package/package/components/Auth0Setting.svelte +8 -3
  3. package/package/components/Dev.svelte +5 -4
  4. package/package/components/DiffDrawer.svelte +2 -2
  5. package/package/components/DiffEditor.svelte +34 -37
  6. package/package/components/DiffEditor.svelte.d.ts +23 -39
  7. package/package/components/EditableSchemaForm.svelte +67 -67
  8. package/package/components/EditableSchemaForm.svelte.d.ts +3 -3
  9. package/package/components/Editor.svelte +32 -11
  10. package/package/components/Editor.svelte.d.ts +6 -0
  11. package/package/components/EditorBar.svelte +2 -2
  12. package/package/components/EditorBar.svelte.d.ts +1 -0
  13. package/package/components/FieldHeader.svelte +1 -1
  14. package/package/components/FlowBuilder.svelte +7 -4
  15. package/package/components/FlowPreviewContent.svelte +3 -3
  16. package/package/components/FlowStatusViewer.svelte +28 -0
  17. package/package/components/FlowStatusViewerInner.svelte +72 -20
  18. package/package/components/FlowStatusViewerInner.svelte.d.ts +7 -0
  19. package/package/components/ModulePreview.svelte +2 -1
  20. package/package/components/ModulePreview.svelte.d.ts +1 -0
  21. package/package/components/ModulePreviewForm.svelte +72 -65
  22. package/package/components/ModulePreviewResultViewer.svelte +13 -18
  23. package/package/components/ModuleTest.svelte +10 -6
  24. package/package/components/ModuleTest.svelte.d.ts +1 -0
  25. package/package/components/OktaSetting.svelte +8 -3
  26. package/package/components/Portal.svelte +11 -7
  27. package/package/components/Portal.svelte.d.ts +19 -39
  28. package/package/components/ResourceEditor.svelte +4 -0
  29. package/package/components/RunForm.svelte +2 -2
  30. package/package/components/RunForm.svelte.d.ts +1 -1
  31. package/package/components/RunFormAdvancedPopup.svelte +13 -1
  32. package/package/components/SchemaForm.svelte +1 -2
  33. package/package/components/ScriptBuilder.svelte +1 -1
  34. package/package/components/ScriptEditor.svelte +22 -7
  35. package/package/components/SimpleEditor.svelte +0 -1
  36. package/package/components/StringTypeNarrowing.svelte.d.ts +1 -1
  37. package/package/components/apps/components/layout/AppModal.svelte +2 -2
  38. package/package/components/apps/editor/component/ComponentNavigation.svelte +3 -2
  39. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptEditor.svelte +1 -1
  40. package/package/components/apps/editor/inlineScriptsPanel/InlineScriptRunnableByPath.svelte +0 -1
  41. package/package/components/apps/editor/settingsPanel/ArrayStaticInputEditor.svelte +3 -1
  42. package/package/components/apps/editor/settingsPanel/GridCondition.svelte +3 -1
  43. package/package/components/apps/editor/settingsPanel/GridNavbar.svelte +3 -1
  44. package/package/components/apps/editor/settingsPanel/GridTab.svelte +3 -1
  45. package/package/components/apps/editor/settingsPanel/OneOfInputSpecsEditor.svelte +55 -53
  46. package/package/components/apps/editor/settingsPanel/TableActions.svelte +3 -1
  47. package/package/components/common/button/model.d.ts +1 -1
  48. package/package/components/common/drawer/Disposable.svelte +51 -30
  49. package/package/components/common/drawer/Disposable.svelte.d.ts +12 -44
  50. package/package/components/common/drawer/Drawer.svelte +15 -11
  51. package/package/components/copilot/FlowInlineScriptAIButton.svelte +4 -2
  52. package/package/components/copilot/FlowInlineScriptAIButton.svelte.d.ts +4 -1
  53. package/package/components/copilot/MetadataGen.svelte +14 -3
  54. package/package/components/copilot/autocomplete/Autocompletor.js +0 -2
  55. package/package/components/copilot/chat/AIChat.svelte +2 -4
  56. package/package/components/copilot/chat/AIChatInput.svelte +3 -3
  57. package/package/components/copilot/chat/AIChatManager.svelte.js +24 -12
  58. package/package/components/copilot/chat/AvailableContextList.svelte +243 -26
  59. package/package/components/copilot/chat/AvailableContextList.svelte.d.ts +2 -1
  60. package/package/components/copilot/chat/ContextElementBadge.svelte +31 -15
  61. package/package/components/copilot/chat/ContextElementBadge.svelte.d.ts +5 -20
  62. package/package/components/copilot/chat/ContextManager.svelte.d.ts +15 -2
  63. package/package/components/copilot/chat/ContextManager.svelte.js +134 -24
  64. package/package/components/copilot/chat/ContextTextarea.svelte +22 -49
  65. package/package/components/copilot/chat/ToolContentDisplay.svelte +10 -1
  66. package/package/components/copilot/chat/ToolExecutionDisplay.svelte +3 -3
  67. package/package/components/copilot/chat/context.d.ts +19 -1
  68. package/package/components/copilot/chat/context.js +1 -0
  69. package/package/components/copilot/chat/flow/FlowAIChat.svelte +109 -7
  70. package/package/components/copilot/chat/flow/core.d.ts +13 -1
  71. package/package/components/copilot/chat/flow/core.js +171 -19
  72. package/package/components/copilot/chat/flow/uiIntents.d.ts +8 -0
  73. package/package/components/copilot/chat/flow/uiIntents.js +5 -0
  74. package/package/components/copilot/chat/flow/useUiIntent.d.ts +5 -0
  75. package/package/components/copilot/chat/flow/useUiIntent.js +12 -0
  76. package/package/components/copilot/chat/monaco-adapter.d.ts +22 -4
  77. package/package/components/copilot/chat/monaco-adapter.js +55 -16
  78. package/package/components/copilot/chat/script/core.d.ts +2 -2
  79. package/package/components/copilot/chat/script/core.js +54 -124
  80. package/package/components/copilot/chat/shared.d.ts +14 -2
  81. package/package/components/copilot/chat/shared.js +170 -7
  82. package/package/components/copilot/lib.js +12 -7
  83. package/package/components/copilot/shared.d.ts +1 -1
  84. package/package/components/copilot/shared.js +16 -10
  85. package/package/components/flows/FlowEditor.svelte +15 -1
  86. package/package/components/flows/FlowEditor.svelte.d.ts +1 -0
  87. package/package/components/flows/FlowModuleIcon.svelte +39 -0
  88. package/package/components/flows/FlowModuleIcon.svelte.d.ts +10 -0
  89. package/package/components/flows/common/FlowCardHeader.svelte +4 -1
  90. package/package/components/flows/content/FlowBranchesAllWrapper.svelte +6 -0
  91. package/package/components/flows/content/FlowBranchesOneWrapper.svelte +6 -0
  92. package/package/components/flows/content/FlowEditorPanel.svelte +2 -1
  93. package/package/components/flows/content/FlowEditorPanel.svelte.d.ts +1 -0
  94. package/package/components/flows/content/FlowInput.svelte +31 -34
  95. package/package/components/flows/content/FlowInput.svelte.d.ts +1 -0
  96. package/package/components/flows/content/FlowLoop.svelte +7 -0
  97. package/package/components/flows/content/FlowModuleComponent.svelte +39 -44
  98. package/package/components/flows/content/FlowModuleScript.svelte +1 -1
  99. package/package/components/flows/content/FlowModuleSuspend.svelte +16 -18
  100. package/package/components/flows/content/FlowWhileLoop.svelte +6 -0
  101. package/package/components/flows/content/ScriptEditorDrawer.svelte +9 -11
  102. package/package/components/flows/dfs.d.ts +1 -1
  103. package/package/components/flows/dfs.js +6 -6
  104. package/package/components/flows/flowInfers.js +7 -7
  105. package/package/components/flows/flowStateUtils.svelte.js +1 -2
  106. package/package/components/flows/map/FlowModuleSchemaItem.svelte +12 -26
  107. package/package/components/flows/map/MapItem.svelte +12 -39
  108. package/package/components/flows/map/VirtualItem.svelte +1 -1
  109. package/package/components/flows/pickers/TopLevelNode.svelte +1 -1
  110. package/package/components/flows/propPicker/InputPickerInner.svelte +5 -5
  111. package/package/components/flows/propPicker/OutputPickerInner.svelte +143 -118
  112. package/package/components/flows/propPicker/OutputPickerInner.svelte.d.ts +7 -16
  113. package/package/components/flows/{testSteps.svelte.d.ts → stepsInputArgs.svelte.d.ts} +2 -1
  114. package/package/components/flows/{testSteps.svelte.js → stepsInputArgs.svelte.js} +15 -3
  115. package/package/components/flows/types.d.ts +16 -3
  116. package/package/components/flows/utils.js +3 -0
  117. package/package/components/graph/FlowGraphV2.svelte +1 -1
  118. package/package/components/graph/renderers/nodes/AIToolNode.svelte +4 -4
  119. package/package/components/graph/renderers/nodes/NewAIToolNode.svelte +71 -54
  120. package/package/components/propertyPicker/ObjectViewer.svelte +11 -3
  121. package/package/components/raw_apps/RawAppInlineScriptEditor.svelte +1 -1
  122. package/package/components/schema/AddPropertyV2.svelte +2 -7
  123. package/package/components/schema/AddPropertyV2.svelte.d.ts +3 -20
  124. package/package/components/schema/EditableSchemaDrawer.svelte +109 -115
  125. package/package/components/schema/EditableSchemaDrawer.svelte.d.ts +2 -1
  126. package/package/components/schema/EditableSchemaSdkWrapper.svelte +16 -3
  127. package/package/components/schema/EditableSchemaSdkWrapper.svelte.d.ts +4 -1
  128. package/package/components/schema/EditableSchemaWrapper.svelte +3 -10
  129. package/package/components/schema/FlowPropertyEditor.svelte +83 -57
  130. package/package/components/schema/FlowPropertyEditor.svelte.d.ts +1 -1
  131. package/package/components/schema/PropertyEditor.svelte.d.ts +1 -1
  132. package/package/components/schema/SchemaFormDND.svelte +11 -10
  133. package/package/components/schema/SchemaFormDND.svelte.d.ts +3 -2
  134. package/package/components/schema/editable_schema_wrapper.d.ts +0 -3
  135. package/package/components/schema/jsonSchemaResource.svelte.d.ts +2 -0
  136. package/package/components/schema/jsonSchemaResource.svelte.js +40 -0
  137. package/package/components/settings/PremiumInfo.svelte +7 -2
  138. package/package/components/triggers/CaptureWrapper.svelte +2 -13
  139. package/package/components/triggers/CaptureWrapper.svelte.d.ts +1 -1
  140. package/package/components/triggers/TriggersWrapper.svelte +1 -0
  141. package/package/components/triggers/http/RouteEditorInner.svelte +1 -1
  142. package/package/components/triggers/nats/NatsTriggerEditorInner.svelte +23 -20
  143. package/package/components/triggers/nats/NatsTriggersConfigSection.svelte +15 -27
  144. package/package/components/triggers/nats/NatsTriggersConfigSection.svelte.d.ts +7 -5
  145. package/package/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +16 -16
  146. package/package/hubPaths.json +3 -1
  147. package/package/script_helpers.d.ts +2 -2
  148. package/package/script_helpers.js +2 -0
  149. package/package/stores.d.ts +1 -0
  150. package/package/stores.js +8 -1
  151. package/package/utils.d.ts +1 -1
  152. package/package.json +14 -14
  153. package/package/components/ModulePreviewResultViewer.svelte.d.ts +0 -28
@@ -10,7 +10,7 @@ let contextTooltipWord = $state('');
10
10
  let tooltipPosition = $state({ x: 0, y: 0 });
11
11
  let textarea = $state(undefined);
12
12
  let tooltipElement = $state(undefined);
13
- let selectedSuggestionIndex = $state(0);
13
+ let tooltipCurrentViewNumber = $state(0);
14
14
  // Properties to copy for caret position calculation
15
15
  const properties = [
16
16
  'direction',
@@ -119,7 +119,7 @@ function getCaretCoordinates(element, position) {
119
119
  return coordinates;
120
120
  }
121
121
  function getHighlightedText(text) {
122
- return text.replace(/@[\w/.-]+/g, (match) => {
122
+ return text.replace(/@[\w/.\-\[\]]+/g, (match) => {
123
123
  const contextElement = availableContext.find((c) => c.title === match.slice(1));
124
124
  if (contextElement) {
125
125
  return `<span class="bg-black dark:bg-white text-white dark:text-black z-10">${match}</span>`;
@@ -142,18 +142,17 @@ function handleContextSelection(contextElement) {
142
142
  updateInstructionsWithContext(contextElement);
143
143
  showContextTooltip = false;
144
144
  }
145
- async function updateTooltipPosition(availableContext, showContextTooltip, contextTooltipWord) {
146
- if (!textarea || !showContextTooltip)
145
+ async function updateTooltipPosition(currentViewItemsNumber) {
146
+ if (!textarea)
147
147
  return;
148
148
  try {
149
149
  const coords = getCaretCoordinates(textarea, textarea.selectionEnd);
150
150
  const rect = textarea.getBoundingClientRect();
151
- const filteredAvailableContext = availableContext.filter((c) => !contextTooltipWord || c.title.toLowerCase().includes(contextTooltipWord.slice(1)));
152
151
  const itemHeight = 28; // Estimated height of one item + gap (Button: p-1(8px) + text-xs(16px) = 24px; Parent: gap-1(4px) = 28px)
153
152
  const containerPadding = 8; // p-1 top + p-1 bottom = 4px + 4px = 8px
154
153
  const maxHeight = 192 + containerPadding; // max-h-48 (192px) + containerPadding (8px)
155
154
  // Calculate uncapped height, subtract gap from last item as it's not needed
156
- const numItems = filteredAvailableContext.length;
155
+ const numItems = currentViewItemsNumber;
157
156
  let uncappedHeight = numItems > 0 ? numItems * itemHeight - 4 + containerPadding : containerPadding;
158
157
  // Ensure height is at least containerPadding even if no items
159
158
  uncappedHeight = Math.max(uncappedHeight, containerPadding);
@@ -211,59 +210,29 @@ function handleInput(e) {
211
210
  else {
212
211
  showContextTooltip = false;
213
212
  contextTooltipWord = '';
214
- selectedSuggestionIndex = 0;
215
- }
216
- }
217
- function handleKeyPress(e) {
218
- if (e.key === 'Enter' && !e.shiftKey) {
219
- e.preventDefault();
220
- if (contextTooltipWord) {
221
- const filteredContext = availableContext.filter((c) => !contextTooltipWord || c.title.toLowerCase().includes(contextTooltipWord.slice(1)));
222
- const contextElement = filteredContext[selectedSuggestionIndex];
223
- if (contextElement) {
224
- const isInSelectedContext = selectedContext.find((c) => c.title === contextElement.title && c.type === contextElement.type);
225
- // If the context element is already in the selected context and the last word in the instructions is the same as the context element title, send request
226
- if (isInSelectedContext && value.split(' ').pop() === '@' + contextElement.title) {
227
- onSendRequest();
228
- return;
229
- }
230
- handleContextSelection(contextElement);
231
- }
232
- else if (contextTooltipWord === '@' && availableContext.length > 0) {
233
- handleContextSelection(availableContext[0]);
234
- }
235
- }
236
- else {
237
- onSendRequest();
238
- }
239
213
  }
240
214
  }
241
215
  function handleKeyDown(e) {
216
+ // Pass to parent first if provided
242
217
  if (onKeyDown) {
243
218
  onKeyDown(e);
244
219
  }
245
- if (!showContextTooltip)
246
- return;
247
- const filteredContext = availableContext.filter((c) => !contextTooltipWord || c.title.toLowerCase().includes(contextTooltipWord.slice(1)));
248
- if (e.key === 'Tab') {
249
- e.preventDefault();
250
- const contextElement = filteredContext[selectedSuggestionIndex];
251
- if (contextElement) {
252
- handleContextSelection(contextElement);
220
+ if (showContextTooltip) {
221
+ // avoid new line after Enter in the tooltip
222
+ if (e.key === 'Enter') {
223
+ e.preventDefault();
253
224
  }
225
+ return;
254
226
  }
255
- if (e.key === 'ArrowDown') {
256
- e.preventDefault();
257
- selectedSuggestionIndex = (selectedSuggestionIndex + 1) % filteredContext.length;
258
- }
259
- else if (e.key === 'ArrowUp') {
227
+ if (e.key === 'Enter' && !e.shiftKey) {
260
228
  e.preventDefault();
261
- selectedSuggestionIndex =
262
- (selectedSuggestionIndex - 1 + filteredContext.length) % filteredContext.length;
229
+ onSendRequest();
263
230
  }
264
231
  }
265
232
  $effect(() => {
266
- updateTooltipPosition(availableContext, showContextTooltip, contextTooltipWord);
233
+ if (showContextTooltip) {
234
+ updateTooltipPosition(tooltipCurrentViewNumber);
235
+ }
267
236
  });
268
237
  export function focus() {
269
238
  textarea?.focus();
@@ -283,7 +252,6 @@ export function focus() {
283
252
  </div>
284
253
  <textarea
285
254
  bind:this={textarea}
286
- onkeypress={handleKeyPress}
287
255
  onkeydown={handleKeyDown}
288
256
  bind:value
289
257
  use:autosize
@@ -319,7 +287,12 @@ export function focus() {
319
287
  }}
320
288
  showAllAvailable={true}
321
289
  stringSearch={contextTooltipWord.slice(1)}
322
- selectedIndex={selectedSuggestionIndex}
290
+ onViewChange={(newNumber) => {
291
+ tooltipCurrentViewNumber = newNumber
292
+ }}
293
+ setShowing={(showing) => {
294
+ showContextTooltip = showing
295
+ }}
323
296
  />
324
297
  </div>
325
298
  </Portal>
@@ -13,6 +13,13 @@ function formatJson(obj) {
13
13
  return obj;
14
14
  }
15
15
  }
16
+ for (const key in obj) {
17
+ try {
18
+ const parsed = JSON.parse(obj[key]);
19
+ obj[key] = parsed;
20
+ }
21
+ catch { }
22
+ }
16
23
  return JSON.stringify(obj, null, 2);
17
24
  }
18
25
  catch {
@@ -71,7 +78,9 @@ async function copyToClipboard() {
71
78
  <div
72
79
  class="bg-surface-secondary border border-gray-200 dark:border-gray-700 rounded p-3 overflow-x-auto max-h-64 overflow-y-auto"
73
80
  >
74
- <pre class="text-2xs text-primary whitespace-pre-wrap">{formatJson(content)}</pre>
81
+ <pre class="text-2xs text-primary whitespace-pre-wrap"
82
+ >{formatJson($state.snapshot(content))}</pre
83
+ >
75
84
  </div>
76
85
  {:else}
77
86
  <div
@@ -14,8 +14,8 @@ const hasParameters = $derived(message.parameters !== undefined && Object.keys(m
14
14
  <!-- Collapsible Header -->
15
15
  <button
16
16
  class={twMerge(
17
- "w-full p-3 bg-surface-secondary hover:bg-surface-hover transition-colors flex items-center justify-between text-left border-b border-gray-200 dark:border-gray-700",
18
- message.needsConfirmation ? "opacity-80" : ""
17
+ 'w-full p-3 bg-surface-secondary hover:bg-surface-hover transition-colors flex items-center justify-between text-left border-b border-gray-200 dark:border-gray-700',
18
+ message.needsConfirmation ? 'opacity-80' : ''
19
19
  )}
20
20
  onclick={() => (isExpanded = !isExpanded)}
21
21
  disabled={!message.showDetails}
@@ -46,7 +46,7 @@ const hasParameters = $derived(message.parameters !== undefined && Object.keys(m
46
46
  {#if isExpanded}
47
47
  <div class="p-3 bg-surface space-y-3">
48
48
  <!-- Parameters Section -->
49
- <div class={message.needsConfirmation ? "opacity-80" : ""}>
49
+ <div class={message.needsConfirmation ? 'opacity-80' : ''}>
50
50
  <ToolContentDisplay title="Parameters" content={message.parameters} />
51
51
  </div>
52
52
 
@@ -40,5 +40,23 @@ export interface CodePieceElement {
40
40
  title: string;
41
41
  lang: ScriptLang | 'bunnative';
42
42
  }
43
- export type ContextElement = CodeElement | ErrorElement | DBElement | DiffElement | CodePieceElement;
43
+ export interface FlowModuleElement {
44
+ type: 'flow_module';
45
+ id: string;
46
+ title: string;
47
+ value: {
48
+ language?: ScriptLang | 'bunnative';
49
+ path?: string;
50
+ content?: string;
51
+ type: string;
52
+ };
53
+ }
54
+ export interface FlowModuleCodePieceElement extends Omit<CodePieceElement, 'type'> {
55
+ type: 'flow_module_code_piece';
56
+ id: string;
57
+ value: FlowModuleElement['value'];
58
+ }
59
+ export type ContextElement = (CodeElement | ErrorElement | DBElement | DiffElement | CodePieceElement | FlowModuleElement | FlowModuleCodePieceElement) & {
60
+ deletable?: boolean;
61
+ };
44
62
  export {};
@@ -7,4 +7,5 @@ export const ContextIconMap = {
7
7
  db: Database,
8
8
  diff: Diff,
9
9
  code_piece: Code
10
+ // flow_module type is handled with FlowModuleIcon
10
11
  };
@@ -71,13 +71,10 @@ const flowHelpers = {
71
71
  hasDiff: () => {
72
72
  return Object.keys(affectedModules).length > 0;
73
73
  },
74
- acceptAllModuleActions: () => {
75
- for (const [id, affectedModule] of Object.entries(affectedModules)) {
76
- if (affectedModule.action === 'removed') {
77
- deleteStep(id);
78
- }
74
+ acceptAllModuleActions() {
75
+ for (const id of Object.keys(affectedModules)) {
76
+ this.acceptModuleAction(id);
79
77
  }
80
- affectedModules = {};
81
78
  },
82
79
  rejectAllModuleActions() {
83
80
  for (const id of Object.keys(affectedModules)) {
@@ -151,7 +148,18 @@ const flowHelpers = {
151
148
  if (!newModule) {
152
149
  throw new Error('Module not found');
153
150
  }
154
- newModule.value = oldModule.value;
151
+ // Apply the old code to the editor and hide diff editor if the reverted module is a rawscript
152
+ if (newModule.value.type === 'rawscript' &&
153
+ $currentEditor?.type === 'script' &&
154
+ $currentEditor.stepId === id) {
155
+ const aiChatEditorHandler = $currentEditor.editor.getAiChatEditorHandler();
156
+ if (aiChatEditorHandler) {
157
+ aiChatEditorHandler.revertAll({ disableReviewCallback: true });
158
+ $currentEditor.hideDiffMode();
159
+ }
160
+ }
161
+ Object.keys(newModule).forEach((k) => delete newModule[k]);
162
+ Object.assign(newModule, $state.snapshot(oldModule));
155
163
  }
156
164
  refreshStateStore(flowStore);
157
165
  delete affectedModules[id];
@@ -162,6 +170,15 @@ const flowHelpers = {
162
170
  if (affectedModules[id]?.action === 'removed') {
163
171
  deleteStep(id);
164
172
  }
173
+ if (affectedModules[id]?.action === 'modified' &&
174
+ $currentEditor &&
175
+ $currentEditor.type === 'script' &&
176
+ $currentEditor.stepId === id) {
177
+ const aiChatEditorHandler = $currentEditor.editor.getAiChatEditorHandler();
178
+ if (aiChatEditorHandler) {
179
+ aiChatEditorHandler.keepAll({ disableReviewCallback: true });
180
+ }
181
+ }
165
182
  delete affectedModules[id];
166
183
  },
167
184
  // ai chat tools
@@ -416,6 +433,72 @@ const flowHelpers = {
416
433
  refreshStateStore(flowStore);
417
434
  }
418
435
  setModuleStatus(id, 'modified');
436
+ },
437
+ setForLoopOptions: async (id, opts) => {
438
+ const module = getModule(id);
439
+ if (!module) {
440
+ throw new Error('Module not found');
441
+ }
442
+ if (module.value.type !== 'forloopflow') {
443
+ throw new Error('Module is not a forloopflow');
444
+ }
445
+ // Apply skip_failures if provided
446
+ if (typeof opts.skip_failures === 'boolean') {
447
+ module.value.skip_failures = opts.skip_failures;
448
+ }
449
+ // Apply parallel if provided
450
+ if (typeof opts.parallel === 'boolean') {
451
+ module.value.parallel = opts.parallel;
452
+ }
453
+ // Handle parallelism
454
+ if (opts.parallel === false) {
455
+ // If parallel is disabled, clear parallelism
456
+ module.value.parallelism = undefined;
457
+ }
458
+ else if (opts.parallelism !== undefined) {
459
+ if (opts.parallelism === null) {
460
+ // Explicitly clear parallelism
461
+ module.value.parallelism = undefined;
462
+ }
463
+ else if (module.value.parallel || opts.parallel === true) {
464
+ // Only set parallelism if parallel is enabled
465
+ const n = Math.max(1, Math.floor(Math.abs(opts.parallelism)));
466
+ module.value.parallelism = n;
467
+ }
468
+ }
469
+ refreshStateStore(flowStore);
470
+ setModuleStatus(id, 'modified');
471
+ },
472
+ setModuleControlOptions: async (id, opts) => {
473
+ const module = getModule(id);
474
+ if (!module) {
475
+ throw new Error('Module not found');
476
+ }
477
+ // Handle stop_after_if
478
+ if (typeof opts.stop_after_if === 'boolean') {
479
+ if (opts.stop_after_if === false) {
480
+ module.stop_after_if = undefined;
481
+ }
482
+ else {
483
+ module.stop_after_if = {
484
+ expr: opts.stop_after_if_expr ?? '',
485
+ skip_if_stopped: opts.stop_after_if
486
+ };
487
+ }
488
+ }
489
+ // Handle skip_if
490
+ if (typeof opts.skip_if === 'boolean') {
491
+ if (opts.skip_if === false) {
492
+ module.skip_if = undefined;
493
+ }
494
+ else {
495
+ module.skip_if = {
496
+ expr: opts.skip_if_expr ?? ''
497
+ };
498
+ }
499
+ }
500
+ refreshStateStore(flowStore);
501
+ setModuleStatus(id, 'modified');
419
502
  }
420
503
  };
421
504
  function deleteStep(id) {
@@ -454,6 +537,25 @@ $effect(() => {
454
537
  const cleanup = aiChatManager.listenForCurrentEditorChanges($currentEditor);
455
538
  return cleanup;
456
539
  });
540
+ // Automatically show revert review when selecting a rawscript module with pending changes
541
+ $effect(() => {
542
+ if ($currentEditor?.type === 'script' &&
543
+ $selectedId &&
544
+ affectedModules[$selectedId] &&
545
+ $currentEditor.editor.getAiChatEditorHandler()) {
546
+ const moduleLastSnapshot = getModule($selectedId, lastSnapshot);
547
+ const content = moduleLastSnapshot?.value.type === 'rawscript' ? moduleLastSnapshot.value.content : '';
548
+ if (content.length > 0) {
549
+ untrack(() => $currentEditor.editor.reviewAppliedCode(content, {
550
+ onFinishedReview: () => {
551
+ const id = $selectedId;
552
+ flowHelpers.acceptModuleAction(id);
553
+ $currentEditor.hideDiffMode();
554
+ }
555
+ }));
556
+ }
557
+ }
558
+ });
457
559
  let diffDrawer = $state(undefined);
458
560
  </script>
459
561
 
@@ -2,6 +2,7 @@ import { type FlowModule } from '../../../../gen';
2
2
  import type { ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam } from 'openai/resources/chat/completions.mjs';
3
3
  import { z } from 'zod';
4
4
  import { type Tool } from '../shared';
5
+ import type { ContextElement } from '../context';
5
6
  import type { ExtendedOpenFlow } from '../../../flows/types';
6
7
  export type AIModuleAction = 'added' | 'modified' | 'removed';
7
8
  export interface FlowAIChatHelpers {
@@ -32,6 +33,17 @@ export interface FlowAIChatHelpers {
32
33
  addBranch: (id: string) => Promise<void>;
33
34
  removeBranch: (id: string, branchIndex: number) => Promise<void>;
34
35
  setForLoopIteratorExpression: (id: string, expression: string) => Promise<void>;
36
+ setForLoopOptions: (id: string, opts: {
37
+ skip_failures?: boolean | null;
38
+ parallel?: boolean | null;
39
+ parallelism?: number | null;
40
+ }) => Promise<void>;
41
+ setModuleControlOptions: (id: string, opts: {
42
+ stop_after_if?: boolean | null;
43
+ stop_after_if_expr?: string | null;
44
+ skip_if?: boolean | null;
45
+ skip_if_expr?: string | null;
46
+ }) => Promise<void>;
35
47
  setCode: (id: string, code: string) => Promise<void>;
36
48
  }
37
49
  declare const newStepSchema: z.ZodUnion<[z.ZodObject<{
@@ -130,5 +142,5 @@ export declare function prepareFlowSystemMessage(): ChatCompletionSystemMessageP
130
142
  export declare function prepareFlowUserMessage(instructions: string, flowAndSelectedId?: {
131
143
  flow: ExtendedOpenFlow;
132
144
  selectedId: string;
133
- }): ChatCompletionUserMessageParam;
145
+ }, selectedContext?: ContextElement[]): ChatCompletionUserMessageParam;
134
146
  export {};