windmill-components 1.503.1 → 1.503.4

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 (69) hide show
  1. package/package/components/AppWrapper.svelte +3 -0
  2. package/package/components/Dev.svelte +94 -4
  3. package/package/components/FlowBuilder.svelte +89 -7
  4. package/package/components/FlowPreviewContent.svelte +309 -278
  5. package/package/components/FlowPreviewContent.svelte.d.ts +33 -19
  6. package/package/components/FlowPreviewResult.svelte +74 -0
  7. package/package/components/FlowPreviewResult.svelte.d.ts +21 -0
  8. package/package/components/FlowStatusViewer.svelte +3 -1
  9. package/package/components/FlowStatusViewer.svelte.d.ts +2 -0
  10. package/package/components/FlowStatusViewerInner.svelte +15 -70
  11. package/package/components/FlowStatusWaitingForEvents.svelte +5 -2
  12. package/package/components/FlowStatusWaitingForEvents.svelte.d.ts +1 -0
  13. package/package/components/FlowWrapper.svelte +3 -0
  14. package/package/components/ModuleTest.svelte +26 -24
  15. package/package/components/ResourcePicker.svelte +11 -3
  16. package/package/components/ScriptWrapper.svelte +3 -0
  17. package/package/components/common/button/Button.svelte +2 -1
  18. package/package/components/common/button/Button.svelte.d.ts +2 -1
  19. package/package/components/flows/FlowEditor.svelte +23 -2
  20. package/package/components/flows/FlowEditor.svelte.d.ts +23 -3
  21. package/package/components/flows/content/FlowEditorPanel.svelte +4 -3
  22. package/package/components/flows/content/FlowEditorPanel.svelte.d.ts +12 -2
  23. package/package/components/flows/content/FlowInput.svelte +2 -2
  24. package/package/components/flows/content/FlowInput.svelte.d.ts +1 -1
  25. package/package/components/flows/content/FlowResult.svelte +35 -0
  26. package/package/components/flows/content/FlowResult.svelte.d.ts +17 -0
  27. package/package/components/flows/header/FlowPreviewButtons.svelte +81 -46
  28. package/package/components/flows/map/FlowGraphPreviewButton.svelte +94 -0
  29. package/package/components/flows/map/FlowGraphPreviewButton.svelte.d.ts +17 -0
  30. package/package/components/flows/map/FlowModuleSchemaItem.svelte +296 -285
  31. package/package/components/flows/map/FlowModuleSchemaItem.svelte.d.ts +6 -0
  32. package/package/components/flows/map/FlowModuleSchemaMap.svelte +20 -1
  33. package/package/components/flows/map/FlowModuleSchemaMap.svelte.d.ts +20 -1
  34. package/package/components/flows/map/MapItem.svelte +25 -3
  35. package/package/components/flows/map/MapItem.svelte.d.ts +6 -1
  36. package/package/components/flows/map/VirtualItem.svelte +55 -3
  37. package/package/components/flows/map/VirtualItem.svelte.d.ts +13 -1
  38. package/package/components/flows/map/VirtualItemWrapper.svelte +33 -29
  39. package/package/components/flows/map/VirtualItemWrapper.svelte.d.ts +1 -0
  40. package/package/components/flows/propPicker/OutputPicker.svelte +17 -2
  41. package/package/components/flows/propPicker/OutputPicker.svelte.d.ts +4 -0
  42. package/package/components/flows/propPicker/OutputPickerInner.svelte +2 -2
  43. package/package/components/flows/propPicker/OutputPickerInner.svelte.d.ts +1 -0
  44. package/package/components/flows/types.d.ts +3 -0
  45. package/package/components/flows/utils.d.ts +9 -0
  46. package/package/components/flows/utils.js +39 -0
  47. package/package/components/graph/FlowGraphV2.svelte +27 -4
  48. package/package/components/graph/FlowGraphV2.svelte.d.ts +18 -2
  49. package/package/components/graph/ViewportResizer.svelte +33 -1
  50. package/package/components/graph/ViewportResizer.svelte.d.ts +5 -1
  51. package/package/components/graph/graphBuilder.svelte.d.ts +26 -1
  52. package/package/components/graph/graphBuilder.svelte.js +13 -3
  53. package/package/components/graph/renderers/edges/BaseEdge.svelte +69 -2
  54. package/package/components/graph/renderers/edges/BaseEdge.svelte.d.ts +10 -0
  55. package/package/components/graph/renderers/nodes/InputNode.svelte +19 -1
  56. package/package/components/graph/renderers/nodes/ModuleNode.svelte +17 -2
  57. package/package/components/graph/renderers/nodes/ResultNode.svelte +9 -8
  58. package/package/components/modulesTest.svelte.d.ts +12 -0
  59. package/package/components/modulesTest.svelte.js +8 -0
  60. package/package/components/preview/FlowPreviewStatus.svelte +9 -4
  61. package/package/components/preview/FlowPreviewStatus.svelte.d.ts +6 -18
  62. package/package/components/schema/EditableSchemaSdkWrapper.svelte +3 -0
  63. package/package/components/workspaceSettings/AISettings.svelte +1 -0
  64. package/package/gen/schemas.gen.d.ts +0 -3
  65. package/package/gen/schemas.gen.js +0 -3
  66. package/package/gen/types.gen.d.ts +0 -1
  67. package/package/utils.js +2 -0
  68. package/package.json +1 -1
  69. package/package/components/flows/header/FlowPreviewButtons.svelte.d.ts +0 -26
@@ -20,7 +20,7 @@ import { Button } from '../../common';
20
20
  import ModuleTest from '../../ModuleTest.svelte';
21
21
  import { getStepHistoryLoaderContext } from '../../stepHistoryLoader.svelte';
22
22
  import { aiModuleActionToBgColor } from '../../copilot/chat/flow/utils';
23
- let { selected = false, deletable = false, retry = false, cache = false, earlyStop = false, skip = false, suspend = false, sleep = false, mock = { enabled: false }, bold = false, id = undefined, label, path = '', modType = undefined, bgColor = '', bgHoverColor = '', concurrency = false, retries = undefined, warningMessage = undefined, isTrigger = false, editMode = false, alwaysShowOutputPicker = false, loopStatus = undefined, icon, onTestUpTo, inputTransform, onUpdateMock, onEditInput, enableTestRun = false } = $props();
23
+ let { selected = false, deletable = false, retry = false, cache = false, earlyStop = false, skip = false, suspend = false, sleep = false, mock = { enabled: false }, bold = false, id = undefined, label, path = '', modType = undefined, bgColor = '', bgHoverColor = '', concurrency = false, retries = undefined, warningMessage = undefined, isTrigger = false, editMode = false, alwaysShowOutputPicker = false, loopStatus = undefined, icon, onTestUpTo, inputTransform, onUpdateMock, onEditInput, flowJob, enableTestRun = false, type, darkMode, skipped } = $props();
24
24
  let pickableIds = $state(undefined);
25
25
  const flowEditorContext = getContext('FlowEditorContext');
26
26
  const flowInputsStore = flowEditorContext?.flowInputsStore;
@@ -80,6 +80,7 @@ let isConnectingCandidate = $derived(!!id && !!$flowPropPickerConfig && !!pickab
80
80
  const outputPickerVisible = $derived(editMode && (isConnectingCandidate || alwaysShowOutputPicker) && !!id);
81
81
  const icon_render = $derived(icon);
82
82
  const action = $derived(getAiModuleAction(id));
83
+ let testRunDropdownOpen = $state(false);
83
84
  </script>
84
85
 
85
86
  {#if deletable && id && editId}
@@ -148,310 +149,320 @@ const action = $derived(getAiModuleAction(id));
148
149
  {/if}
149
150
  {/if}
150
151
 
151
- <!-- svelte-ignore a11y_click_events_have_key_events -->
152
- <!-- svelte-ignore a11y_no_static_element_interactions -->
153
- <div
154
- class={classNames(
155
- 'w-full module flex rounded-sm cursor-pointer max-w-full ',
156
- 'flex relative',
157
- deletable ? aiModuleActionToBgColor(action) : ''
158
- )}
159
- style="width: 275px; height: 34px; background-color: {hover && bgHoverColor
160
- ? bgHoverColor
161
- : bgColor};"
162
- onmouseenter={() => (hover = true)}
163
- onmouseleave={() => (hover = false)}
164
- onpointerdown={stopPropagation(preventDefault(() => dispatch('pointerdown')))}
165
- >
166
- {#if deletable}
167
- <ModuleAcceptReject {action} {id} />
168
- {/if}
152
+ <div class="relative">
153
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
154
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
169
155
  <div
170
156
  class={classNames(
171
- 'absolute rounded-sm outline-offset-0 outline-slate-500 dark:outline-gray-400',
172
- selected ? 'outline outline-2' : 'active:outline active:outline-2'
157
+ 'w-full module flex rounded-sm cursor-pointer max-w-full',
158
+ deletable ? aiModuleActionToBgColor(action) : ''
173
159
  )}
174
- style={`width: 275px; height: ${outputPickerVisible ? '51px' : '34px'};`}
175
- ></div>
176
- <div
177
- class="absolute text-sm right-2 flex flex-row gap-1 z-10 transition-all duration-100"
178
- style={`bottom: ${outputPickerBarOpen ? '-38px' : '-12px'}`}
160
+ style="width: 275px; height: 34px; background-color: {hover && bgHoverColor
161
+ ? bgHoverColor
162
+ : bgColor};"
163
+ onmouseenter={() => (hover = true)}
164
+ onmouseleave={() => (hover = false)}
165
+ onpointerdown={stopPropagation(preventDefault(() => dispatch('pointerdown')))}
179
166
  >
180
- {#if retry}
181
- <Popover notClickable>
182
- <div
183
- transition:fade|local={{ duration: 200 }}
184
- class="center-center rounded border bg-surface border-gray-400 text-secondary px-1 py-0.5"
185
- >
186
- {#if retries}<span class="text-red-400 mr-2">{retries}</span>{/if}
187
- <Repeat size={12} />
188
- </div>
189
- {#snippet text()}
190
- Retries
191
- {/snippet}
192
- </Popover>
167
+ {#if deletable}
168
+ <ModuleAcceptReject {action} {id} />
193
169
  {/if}
170
+ <div
171
+ class={classNames(
172
+ 'absolute rounded-sm outline-offset-0 outline-slate-500 dark:outline-gray-400',
173
+ selected ? 'outline outline-2' : 'active:outline active:outline-2'
174
+ )}
175
+ style={`width: 275px; height: ${outputPickerVisible ? '51px' : '34px'};`}
176
+ ></div>
177
+ <div
178
+ class="absolute text-sm right-2 flex flex-row gap-1 z-10 transition-all duration-100"
179
+ style={`bottom: ${outputPickerBarOpen ? '-38px' : '-12px'}`}
180
+ >
181
+ {#if retry}
182
+ <Popover notClickable>
183
+ <div
184
+ transition:fade|local={{ duration: 200 }}
185
+ class="center-center rounded border bg-surface border-gray-400 text-secondary px-1 py-0.5"
186
+ >
187
+ {#if retries}<span class="text-red-400 mr-2">{retries}</span>{/if}
188
+ <Repeat size={12} />
189
+ </div>
190
+ {#snippet text()}
191
+ Retries
192
+ {/snippet}
193
+ </Popover>
194
+ {/if}
194
195
 
195
- {#if concurrency}
196
- <Popover notClickable>
197
- <div
198
- transition:fade|local={{ duration: 200 }}
199
- class="center-center rounded border bg-surface border-gray-400 text-secondary px-1 py-0.5"
200
- >
201
- <Gauge size={12} />
202
- </div>
203
- {#snippet text()}
204
- Concurrency Limits
205
- {/snippet}
206
- </Popover>
207
- {/if}
208
- {#if cache}
209
- <Popover notClickable>
210
- <div
211
- transition:fade|local={{ duration: 200 }}
212
- class="center-center rounded border bg-surface border-gray-400 text-secondary px-1 py-0.5"
213
- >
214
- <Database size={12} />
215
- </div>
216
- {#snippet text()}
217
- Cached
218
- {/snippet}
219
- </Popover>
220
- {/if}
221
- {#if earlyStop}
222
- <Popover notClickable>
223
- <div
224
- transition:fade|local={{ duration: 200 }}
225
- class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
226
- >
227
- <Square size={12} />
228
- </div>
229
- {#snippet text()}
230
- {isTrigger ? 'Stop early if there are no new events' : 'Early stop/break'}
231
- {/snippet}
232
- </Popover>
233
- {/if}
234
- {#if skip}
235
- <Popover notClickable>
236
- <div
237
- transition:fade|local={{ duration: 200 }}
238
- class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
239
- >
240
- <SkipForward size={12} />
241
- </div>
242
- {#snippet text()}
243
- Skip
244
- {/snippet}
245
- </Popover>
246
- {/if}
247
- {#if suspend}
248
- <Popover notClickable>
249
- <div
250
- transition:fade|local={{ duration: 200 }}
251
- class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
252
- >
253
- <PhoneIncoming size={12} />
254
- </div>
255
- {#snippet text()}
256
- Suspend
257
- {/snippet}
258
- </Popover>
259
- {/if}
260
- {#if sleep}
261
- <Popover notClickable>
262
- <div
263
- transition:fade|local={{ duration: 200 }}
264
- class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
265
- >
266
- <Bed size={12} />
267
- </div>
268
- {#snippet text()}
269
- Sleep
270
- {/snippet}
271
- </Popover>
272
- {/if}
273
- {#if mock?.enabled}
274
- <Popover notClickable>
275
- <button
276
- transition:fade|local={{ duration: 200 }}
277
- class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
278
- onclick={() => {
279
- outputPicker?.toggleOpen()
280
- }}
281
- data-popover
282
- >
283
- <Pin size={12} />
284
- </button>
285
- {#snippet text()}
286
- Pinned
287
- {/snippet}
288
- </Popover>
289
- {/if}
290
- </div>
196
+ {#if concurrency}
197
+ <Popover notClickable>
198
+ <div
199
+ transition:fade|local={{ duration: 200 }}
200
+ class="center-center rounded border bg-surface border-gray-400 text-secondary px-1 py-0.5"
201
+ >
202
+ <Gauge size={12} />
203
+ </div>
204
+ {#snippet text()}
205
+ Concurrency Limits
206
+ {/snippet}
207
+ </Popover>
208
+ {/if}
209
+ {#if cache}
210
+ <Popover notClickable>
211
+ <div
212
+ transition:fade|local={{ duration: 200 }}
213
+ class="center-center rounded border bg-surface border-gray-400 text-secondary px-1 py-0.5"
214
+ >
215
+ <Database size={12} />
216
+ </div>
217
+ {#snippet text()}
218
+ Cached
219
+ {/snippet}
220
+ </Popover>
221
+ {/if}
222
+ {#if earlyStop}
223
+ <Popover notClickable>
224
+ <div
225
+ transition:fade|local={{ duration: 200 }}
226
+ class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
227
+ >
228
+ <Square size={12} />
229
+ </div>
230
+ {#snippet text()}
231
+ {isTrigger ? 'Stop early if there are no new events' : 'Early stop/break'}
232
+ {/snippet}
233
+ </Popover>
234
+ {/if}
235
+ {#if skip}
236
+ <Popover notClickable>
237
+ <div
238
+ transition:fade|local={{ duration: 200 }}
239
+ class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
240
+ >
241
+ <SkipForward size={12} />
242
+ </div>
243
+ {#snippet text()}
244
+ Skip
245
+ {/snippet}
246
+ </Popover>
247
+ {/if}
248
+ {#if suspend}
249
+ <Popover notClickable>
250
+ <div
251
+ transition:fade|local={{ duration: 200 }}
252
+ class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
253
+ >
254
+ <PhoneIncoming size={12} />
255
+ </div>
256
+ {#snippet text()}
257
+ Suspend
258
+ {/snippet}
259
+ </Popover>
260
+ {/if}
261
+ {#if sleep}
262
+ <Popover notClickable>
263
+ <div
264
+ transition:fade|local={{ duration: 200 }}
265
+ class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
266
+ >
267
+ <Bed size={12} />
268
+ </div>
269
+ {#snippet text()}
270
+ Sleep
271
+ {/snippet}
272
+ </Popover>
273
+ {/if}
274
+ {#if mock?.enabled}
275
+ <Popover notClickable>
276
+ <button
277
+ transition:fade|local={{ duration: 200 }}
278
+ class="center-center bg-surface rounded border border-gray-400 text-secondary px-1 py-0.5"
279
+ onclick={() => {
280
+ outputPicker?.toggleOpen()
281
+ }}
282
+ data-popover
283
+ >
284
+ <Pin size={12} />
285
+ </button>
286
+ {#snippet text()}
287
+ Pinned
288
+ {/snippet}
289
+ </Popover>
290
+ {/if}
291
+ </div>
291
292
 
292
- <div
293
- class={twMerge('flex flex-col w-full', deletable && action === 'removed' ? 'opacity-50' : '')}
294
- >
295
- <FlowModuleSchemaItemViewer
296
- {label}
297
- {path}
298
- {id}
299
- deletable={deletable && !action}
300
- {bold}
301
- bind:editId
302
- {hover}
293
+ <div
294
+ class={twMerge('flex flex-col w-full', deletable && action === 'removed' ? 'opacity-50' : '')}
303
295
  >
304
- {#snippet icon()}
305
- {@render icon_render?.()}
306
- {/snippet}
307
- </FlowModuleSchemaItemViewer>
308
-
309
- {#if outputPickerVisible}
310
- <OutputPicker
311
- bind:this={outputPicker}
312
- {selected}
296
+ <FlowModuleSchemaItemViewer
297
+ {label}
298
+ {path}
299
+ {id}
300
+ deletable={deletable && !action}
301
+ {bold}
302
+ bind:editId
313
303
  {hover}
314
- {isConnectingCandidate}
315
- {historyOpen}
316
- {inputTransform}
317
- id={id ?? ''}
318
- bind:bottomBarOpen={outputPickerBarOpen}
319
- {loopStatus}
320
- {onEditInput}
321
304
  >
322
- {#snippet children({ allowCopy, isConnecting, selectConnection })}
323
- <OutputPickerInner
324
- {allowCopy}
325
- prefix={'results'}
326
- connectingData={isConnecting ? connectingData : undefined}
327
- {mock}
328
- {lastJob}
329
- {testJob}
330
- moduleId={id}
331
- onSelect={selectConnection}
332
- {onUpdateMock}
333
- {path}
334
- {loopStatus}
335
- rightMargin
336
- bind:derivedHistoryOpen={historyOpen}
337
- historyOffset={{ mainAxis: 12, crossAxis: -9 }}
338
- clazz="p-1"
339
- isLoading={testIsLoading ||
340
- (id ? stepHistoryLoader?.stepStates[id]?.loadingJobs : false)}
341
- initial={id ? stepHistoryLoader?.stepStates[id]?.initial : undefined}
342
- />
305
+ {#snippet icon()}
306
+ {@render icon_render?.()}
343
307
  {/snippet}
344
- </OutputPicker>
345
- {/if}
346
- </div>
308
+ </FlowModuleSchemaItemViewer>
347
309
 
348
- {#if deletable && !action}
349
- {#if enableTestRun}
350
- <div
351
- class="absolute top-1/2 -translate-y-1/2 -translate-x-[100%] -left-[0] flex items-center w-fit px-2 h-9 min-w-14"
352
- >
353
- {#if (hover || selected) && outputPickerVisible}
354
- <div transition:fade={{ duration: 100 }}>
355
- {#if !testIsLoading}
356
- <Button
357
- size="sm"
358
- color="dark"
359
- title="Run"
360
- btnClasses="p-1.5"
361
- on:click={() => {
362
- outputPicker?.toggleOpen(true)
363
- moduleTest?.loadArgsAndRunTest()
364
- }}
365
- dropdownItems={[
366
- {
367
- label: 'Test up to here',
368
- onClick: () => {
369
- if (id) {
370
- onTestUpTo?.(id)
371
- }
372
- }
373
- }
374
- ]}
375
- dropdownBtnClasses="!w-4 px-1"
376
- >
377
- {#if testIsLoading}
378
- <Loader2 size={12} class="animate-spin" />
379
- {:else}
380
- <Play size={12} />
381
- {/if}
382
- </Button>
383
- {:else}
384
- <Button
385
- size="xs"
386
- color="red"
387
- variant="contained"
388
- btnClasses="!h-[25.5px] !w-[44.5px] !p-1.5 gap-0.5"
389
- on:click={async () => {
390
- moduleTest?.cancelJob()
391
- }}
392
- >
393
- <Loader2 size={10} class="animate-spin mr-0.5" />
394
- <X size={14} />
395
- </Button>
396
- {/if}
397
- </div>
398
- {/if}
399
- </div>
400
- {/if}
401
- <button
402
- class="absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
310
+ {#if outputPickerVisible}
311
+ <OutputPicker
312
+ bind:this={outputPicker}
313
+ {selected}
314
+ {hover}
315
+ {isConnectingCandidate}
316
+ {historyOpen}
317
+ {inputTransform}
318
+ id={id ?? ''}
319
+ bind:bottomBarOpen={outputPickerBarOpen}
320
+ {loopStatus}
321
+ {onEditInput}
322
+ {type}
323
+ {darkMode}
324
+ {skipped}
325
+ >
326
+ {#snippet children({ allowCopy, isConnecting, selectConnection })}
327
+ <OutputPickerInner
328
+ {allowCopy}
329
+ prefix={'results'}
330
+ connectingData={isConnecting ? connectingData : undefined}
331
+ {mock}
332
+ {lastJob}
333
+ {testJob}
334
+ moduleId={id}
335
+ onSelect={selectConnection}
336
+ {onUpdateMock}
337
+ {path}
338
+ {loopStatus}
339
+ rightMargin
340
+ bind:derivedHistoryOpen={historyOpen}
341
+ historyOffset={{ mainAxis: 12, crossAxis: -9 }}
342
+ clazz="p-1"
343
+ isLoading={testIsLoading ||
344
+ (id ? stepHistoryLoader?.stepStates[id]?.loadingJobs : false)}
345
+ initial={id ? stepHistoryLoader?.stepStates[id]?.initial : undefined}
346
+ />
347
+ {/snippet}
348
+ </OutputPicker>
349
+ {/if}
350
+ </div>
351
+
352
+ {#if deletable && !action}
353
+ <button
354
+ class="absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
403
355
  outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-0 hover:bg-red-400 hover:text-white
404
356
  {hover || selected ? '' : '!hidden'}"
405
- title="Delete"
406
- onclick={stopPropagation(
407
- preventDefault((event) => dispatch('delete', { id, type: modType }))
408
- )}
409
- >
410
- <X class="mx-[3px]" size={12} strokeWidth={2} />
411
- </button>
357
+ title="Delete"
358
+ onclick={stopPropagation(
359
+ preventDefault((event) => dispatch('delete', { id, type: modType }))
360
+ )}
361
+ >
362
+ <X class="mx-[3px]" size={12} strokeWidth={2} />
363
+ </button>
412
364
 
413
- {#if id !== 'preprocessor'}
414
- <button
415
- class="absolute -top-[10px] right-[60px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
365
+ {#if id !== 'preprocessor'}
366
+ <button
367
+ class="absolute -top-[10px] right-[60px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
416
368
  outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-0 hover:bg-blue-400 hover:text-white
417
369
  {hover ? '' : '!hidden'}"
418
- onclick={stopPropagation(preventDefault((event) => dispatch('move')))}
419
- title="Move"
420
- >
421
- <Move class="mx-[3px]" size={12} strokeWidth={2} />
422
- </button>
370
+ onclick={stopPropagation(preventDefault((event) => dispatch('move')))}
371
+ title="Move"
372
+ >
373
+ <Move class="mx-[3px]" size={12} strokeWidth={2} />
374
+ </button>
375
+ {/if}
376
+
377
+ {#if (id && Object.values($flowInputsStore?.[id]?.flowStepWarnings || {}).length > 0) || Boolean(warningMessage)}
378
+ <div class="absolute -top-[10px] -left-[10px]">
379
+ <Popover>
380
+ {#snippet text()}
381
+ <ul class="list-disc px-2">
382
+ {#if id}
383
+ {#each Object.values($flowInputsStore?.[id]?.flowStepWarnings || {}) as m}
384
+ <li>
385
+ {m.message}
386
+ </li>
387
+ {/each}
388
+ {/if}
389
+ </ul>
390
+ {/snippet}
391
+ <div
392
+ class={twMerge(
393
+ 'flex items-center justify-center h-full w-full rounded-md p-0.5 border duration-0 ',
394
+ id &&
395
+ Object.values($flowInputsStore?.[id]?.flowStepWarnings || {})?.some(
396
+ (x) => x.type === 'error'
397
+ )
398
+ ? 'border-red-600 text-red-600 bg-red-100 hover:bg-red-300'
399
+ : 'border-yellow-600 text-yellow-600 bg-yellow-100 hover:bg-yellow-300'
400
+ )}
401
+ >
402
+ <AlertTriangle size={14} strokeWidth={2} />
403
+ </div>
404
+ </Popover>
405
+ </div>
406
+ {/if}
423
407
  {/if}
408
+ </div>
424
409
 
425
- {#if (id && Object.values($flowInputsStore?.[id]?.flowStepWarnings || {}).length > 0) || Boolean(warningMessage)}
426
- <div class="absolute -top-[10px] -left-[10px]">
427
- <Popover>
428
- {#snippet text()}
429
- <ul class="list-disc px-2">
430
- {#if id}
431
- {#each Object.values($flowInputsStore?.[id]?.flowStepWarnings || {}) as m}
432
- <li>
433
- {m.message}
434
- </li>
435
- {/each}
410
+ {#if editMode && enableTestRun && flowJob?.type !== 'QueuedJob'}
411
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
412
+ <div
413
+ class="absolute top-1/2 -translate-y-1/2 -translate-x-[100%] -left-[0] flex items-center w-fit px-2 h-9 min-w-14"
414
+ onmouseenter={() => (hover = true)}
415
+ onmouseleave={() => (hover = false)}
416
+ >
417
+ {#if (hover || selected || testRunDropdownOpen) && outputPickerVisible}
418
+ <div transition:fade={{ duration: 100 }}>
419
+ {#if !testIsLoading}
420
+ <Button
421
+ size="sm"
422
+ color="light"
423
+ title="Run"
424
+ variant="border"
425
+ btnClasses="p-1.5"
426
+ on:click={() => {
427
+ outputPicker?.toggleOpen(true)
428
+ moduleTest?.loadArgsAndRunTest()
429
+ }}
430
+ dropdownItems={[
431
+ {
432
+ label: 'Test up to here',
433
+ onClick: () => {
434
+ if (id) {
435
+ onTestUpTo?.(id)
436
+ }
437
+ }
438
+ }
439
+ ]}
440
+ dropdownBtnClasses="!w-4 px-1"
441
+ bind:dropdownOpen={testRunDropdownOpen}
442
+ >
443
+ {#if testIsLoading}
444
+ <Loader2 size={12} class="animate-spin" />
445
+ {:else}
446
+ <Play size={12} />
436
447
  {/if}
437
- </ul>
438
- {/snippet}
439
- <div
440
- class={twMerge(
441
- 'flex items-center justify-center h-full w-full rounded-md p-0.5 border duration-0 ',
442
- id &&
443
- Object.values($flowInputsStore?.[id]?.flowStepWarnings || {})?.some(
444
- (x) => x.type === 'error'
445
- )
446
- ? 'border-red-600 text-red-600 bg-red-100 hover:bg-red-300'
447
- : 'border-yellow-600 text-yellow-600 bg-yellow-100 hover:bg-yellow-300'
448
- )}
449
- >
450
- <AlertTriangle size={14} strokeWidth={2} />
451
- </div>
452
- </Popover>
453
- </div>
454
- {/if}
448
+ </Button>
449
+ {:else}
450
+ <Button
451
+ size="xs"
452
+ color="red"
453
+ variant="contained"
454
+ btnClasses="!h-[25.5px] !w-[44.5px] !p-1.5 gap-0.5"
455
+ on:click={async () => {
456
+ moduleTest?.cancelJob()
457
+ }}
458
+ >
459
+ <Loader2 size={10} class="animate-spin mr-0.5" />
460
+ <X size={14} />
461
+ </Button>
462
+ {/if}
463
+ </div>
464
+ {/if}
465
+ </div>
455
466
  {/if}
456
467
  </div>
457
468
 
@@ -1,3 +1,4 @@
1
+ import type { FlowStatusModule, Job } from '../../../gen';
1
2
  interface Props {
2
3
  selected?: boolean;
3
4
  deletable?: boolean;
@@ -36,7 +37,12 @@ interface Props {
36
37
  return_value?: unknown;
37
38
  }) => void;
38
39
  onEditInput?: (moduleId: string, key: string) => void;
40
+ flowJob?: Job | undefined;
41
+ isOwner?: boolean;
39
42
  enableTestRun?: boolean;
43
+ type?: FlowStatusModule['type'] | undefined;
44
+ darkMode?: boolean;
45
+ skipped?: boolean;
40
46
  }
41
47
  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> {
42
48
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {