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
@@ -16,9 +16,10 @@ import { setScheduledPollSchedule } from '../../triggers';
16
16
  import { JobService } from '../../../gen';
17
17
  import { dfsByModule } from '../previousResults';
18
18
  import { refreshStateStore } from '../../../svelte5Utils.svelte';
19
+ import { writable } from 'svelte/store';
19
20
  import FlowStickyNode from './FlowStickyNode.svelte';
20
21
  import { getStepHistoryLoaderContext } from '../../stepHistoryLoader.svelte';
21
- let { sidebarSize = $bindable(undefined), disableStaticInputs = false, disableTutorials = false, disableAi = false, disableSettings = false, newFlow = false, smallErrorHandler = false, workspace = $workspaceStore, onTestUpTo, onEditInput, aiChatOpen, showFlowAiButton, toggleAiChat } = $props();
22
+ let { sidebarSize = $bindable(undefined), disableStaticInputs = false, disableTutorials = false, disableAi = false, disableSettings = false, newFlow = false, smallErrorHandler = false, workspace = $workspaceStore, onTestUpTo, onEditInput, localModuleStates = writable({}), aiChatOpen, showFlowAiButton, toggleAiChat, isOwner, onTestFlow, isRunning, onCancelTestFlow, onOpenPreview, onHideJobStatus, individualStepTests = false, flowJob = undefined, showJobStatus = false, suspendStatus = writable({}), onDelete, flowHasChanged } = $props();
22
23
  let flowTutorials = $state(undefined);
23
24
  const { customUi, selectedId, moving, history, flowStateStore, flowStore, pathStore } = getContext('FlowEditorContext');
24
25
  const { triggersCount, triggersState } = getContext('TriggerContext');
@@ -158,6 +159,10 @@ export function removeBranch(id, index) {
158
159
  }
159
160
  let deleteCallback = $state(undefined);
160
161
  let dependents = $state({});
162
+ let graph = $state(undefined);
163
+ export function isNodeVisible(nodeId) {
164
+ return graph?.isNodeVisible(nodeId) ?? false;
165
+ }
161
166
  function shouldRunTutorial(tutorialName, name, index) {
162
167
  return ($tutorialsToDo.includes(index) &&
163
168
  name == tutorialName &&
@@ -261,6 +266,7 @@ $effect(() => {
261
266
 
262
267
  <div class="z-10 flex-auto grow bg-surface-secondary" bind:clientHeight={minHeight}>
263
268
  <FlowGraphV2
269
+ bind:this={graph}
264
270
  earlyStop={flowStore.val.value?.skip_expr !== undefined}
265
271
  cache={flowStore.val.value?.cache_ttl !== undefined}
266
272
  triggerNode={customUi?.triggers != false}
@@ -279,6 +285,13 @@ $effect(() => {
279
285
  editMode
280
286
  {onTestUpTo}
281
287
  {onEditInput}
288
+ flowModuleStates={$localModuleStates}
289
+ {isOwner}
290
+ {individualStepTests}
291
+ {flowJob}
292
+ {showJobStatus}
293
+ {suspendStatus}
294
+ {flowHasChanged}
282
295
  onDelete={(id) => {
283
296
  dependents = getDependentComponents(id, flowStore.val)
284
297
  const cb = () => {
@@ -291,6 +304,7 @@ $effect(() => {
291
304
  removeAtId(flowStore.val.value.modules, id)
292
305
  }
293
306
  refreshStateStore(flowStore)
307
+ onDelete?.(id)
294
308
  }
295
309
 
296
310
  if (Object.keys(dependents).length > 0) {
@@ -473,6 +487,11 @@ $effect(() => {
473
487
  module.mock = $state.snapshot(detail.mock)
474
488
  refreshStateStore(flowStore)
475
489
  }}
490
+ {onTestFlow}
491
+ {isRunning}
492
+ {onCancelTestFlow}
493
+ {onOpenPreview}
494
+ {onHideJobStatus}
476
495
  />
477
496
  </div>
478
497
  </div>
@@ -1,5 +1,7 @@
1
- import type { FlowModule } from '../../../gen';
1
+ import type { FlowModule, Job } from '../../../gen';
2
2
  import type { InlineScript, InsertKind } from '../../graph/graphBuilder.svelte';
3
+ import type { GraphModuleState } from '../../graph';
4
+ import { type Writable } from 'svelte/store';
3
5
  interface Props {
4
6
  sidebarSize?: number | undefined;
5
7
  disableStaticInputs?: boolean;
@@ -11,9 +13,25 @@ interface Props {
11
13
  workspace?: string | undefined;
12
14
  onTestUpTo?: ((id: string) => void) | undefined;
13
15
  onEditInput?: (moduleId: string, key: string) => void;
16
+ localModuleStates?: Writable<Record<string, GraphModuleState>>;
14
17
  aiChatOpen?: boolean;
15
18
  showFlowAiButton?: boolean;
16
19
  toggleAiChat?: () => void;
20
+ isOwner?: boolean;
21
+ onTestFlow?: () => void;
22
+ isRunning?: boolean;
23
+ onCancelTestFlow?: () => void;
24
+ onOpenPreview?: () => void;
25
+ onHideJobStatus?: () => void;
26
+ individualStepTests?: boolean;
27
+ flowJob?: Job | undefined;
28
+ showJobStatus?: boolean;
29
+ suspendStatus?: Writable<Record<string, {
30
+ job: Job;
31
+ nb: number;
32
+ }>>;
33
+ onDelete?: (id: string) => void;
34
+ flowHasChanged?: boolean;
17
35
  }
18
36
  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> {
19
37
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -47,6 +65,7 @@ declare const FlowModuleSchemaMap: $$__sveltets_2_IsomorphicComponent<Props, {
47
65
  selectNextId: (id: any) => void;
48
66
  addBranch: (id: string) => Promise<void>;
49
67
  removeBranch: (id: string, index: number) => void;
68
+ isNodeVisible: (nodeId: string) => boolean;
50
69
  setExpr: (module: FlowModule, expr: string) => void;
51
70
  }, "sidebarSize">;
52
71
  type FlowModuleSchemaMap = InstanceType<typeof FlowModuleSchemaMap>;
@@ -10,7 +10,8 @@ import BarsStaggered from '../../icons/BarsStaggered.svelte';
10
10
  import FlowJobsMenu from './FlowJobsMenu.svelte';
11
11
  import { isTriggerStep } from '../../graph/graphBuilder.svelte';
12
12
  import { checkIfParentLoop } from '../utils';
13
- let { onSelectedIteration, moduleId, mod = $bindable(), insertable, annotation = undefined, bgColor = '', bgHoverColor = '', moving = undefined, duration_ms = undefined, retries = undefined, flowJobs, editMode = false, onSelect, onTestUpTo, onUpdateMock, onEditInput } = $props();
13
+ import { twMerge } from 'tailwind-merge';
14
+ let { onSelectedIteration, moduleId, mod = $bindable(), insertable, annotation = undefined, bgColor = '', bgHoverColor = '', moving = undefined, duration_ms = undefined, retries = undefined, flowJobs, editMode = false, onSelect, onTestUpTo, onUpdateMock, onEditInput, flowJob, isOwner = false, type, darkMode, skipped } = $props();
14
15
  const { selectedId } = getContext('FlowGraphContext');
15
16
  const { flowStore } = getContext('FlowEditorContext') || {};
16
17
  const dispatch = createEventDispatcher();
@@ -39,12 +40,22 @@ let parentLoop = $derived(flowStore?.val && mod ? checkIfParentLoop(flowStore.va
39
40
  {/if}
40
41
 
41
42
  {#if duration_ms}
42
- <div class="absolute z-10 right-0 -top-4 center-center text-tertiary text-2xs">
43
+ <div
44
+ class={twMerge(
45
+ 'absolute z-10 right-0 -top-4 center-center text-tertiary text-2xs',
46
+ editMode ? 'text-gray-400 dark:text-gray-500 text-2xs font-normal mr-2' : ''
47
+ )}
48
+ >
43
49
  {msToSec(duration_ms)}s
44
50
  </div>
45
51
  {/if}
46
52
  {#if annotation && annotation != ''}
47
- <div class="absolute z-10 left-0 -top-5 center-center text-tertiary">
53
+ <div
54
+ class={twMerge(
55
+ 'absolute z-10 left-0 -top-5 center-center text-tertiary',
56
+ editMode ? '-top-4 text-gray-400 dark:text-gray-500 text-xs font-normal' : ''
57
+ )}
58
+ >
48
59
  {annotation}
49
60
  </div>
50
61
  {/if}
@@ -92,6 +103,8 @@ let parentLoop = $derived(flowStore?.val && mod ? checkIfParentLoop(flowStore.va
92
103
  alwaysShowOutputPicker={!mod.id.startsWith('subflow:')}
93
104
  loopStatus={{ type: 'self', flow: mod.value.type }}
94
105
  {onTestUpTo}
106
+ {type}
107
+ {darkMode}
95
108
  >
96
109
  {#snippet icon()}
97
110
  <div>
@@ -113,6 +126,8 @@ let parentLoop = $derived(flowStore?.val && mod ? checkIfParentLoop(flowStore.va
113
126
  {bgColor}
114
127
  {bgHoverColor}
115
128
  {onTestUpTo}
129
+ {type}
130
+ {darkMode}
116
131
  >
117
132
  {#snippet icon()}
118
133
  <div>
@@ -134,6 +149,8 @@ let parentLoop = $derived(flowStore?.val && mod ? checkIfParentLoop(flowStore.va
134
149
  {bgColor}
135
150
  {bgHoverColor}
136
151
  {onTestUpTo}
152
+ {type}
153
+ {darkMode}
137
154
  >
138
155
  {#snippet icon()}
139
156
  <div>
@@ -178,7 +195,12 @@ let parentLoop = $derived(flowStore?.val && mod ? checkIfParentLoop(flowStore.va
178
195
  inputTransform={mod.value.type !== 'identity' ? mod.value.input_transforms : undefined}
179
196
  {onTestUpTo}
180
197
  {onEditInput}
198
+ {flowJob}
199
+ {isOwner}
181
200
  enableTestRun
201
+ {type}
202
+ {darkMode}
203
+ {skipped}
182
204
  >
183
205
  {#snippet icon()}
184
206
  <div>
@@ -1,4 +1,4 @@
1
- import type { FlowModule } from '../../../gen';
1
+ import type { FlowModule, FlowStatusModule, Job } from '../../../gen';
2
2
  import { type onSelectedIteration } from '../../graph/graphBuilder.svelte';
3
3
  interface Props {
4
4
  moduleId: string;
@@ -28,6 +28,11 @@ interface Props {
28
28
  };
29
29
  }) => void;
30
30
  onEditInput?: (moduleId: string, key: string) => void;
31
+ flowJob?: Job | undefined;
32
+ isOwner?: boolean;
33
+ type?: FlowStatusModule['type'] | undefined;
34
+ darkMode?: boolean;
35
+ skipped?: boolean;
31
36
  }
32
37
  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> {
33
38
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -7,9 +7,20 @@ import { fade } from 'svelte/transition';
7
7
  import { Database, Square } from 'lucide-svelte';
8
8
  import ModuleAcceptReject, { getAiModuleAction } from '../../copilot/chat/flow/ModuleAcceptReject.svelte';
9
9
  import { aiModuleActionToBgColor } from '../../copilot/chat/flow/utils';
10
- let { label = undefined, bgColor = '', bgHoverColor = '', selected, selectable, id = undefined, center = true, borderColor = undefined, hideId = false, preLabel = undefined, inputJson = undefined, prefix = '', alwaysPluggable = false, cache = false, earlyStop = false, editMode = false, icon, onUpdateMock, onEditInput } = $props();
11
- const outputPickerVisible = $derived((alwaysPluggable || (inputJson && Object.keys(inputJson).length > 0)) && editMode);
10
+ import FlowGraphPreviewButton from './FlowGraphPreviewButton.svelte';
11
+ let { label = undefined, bgColor = '', bgHoverColor = '', selected, selectable, id = undefined, center = true, borderColor = undefined, hideId = false, preLabel = undefined, inputJson = undefined, prefix = '', nodeKind, cache = false, earlyStop = false, editMode = false, icon, onUpdateMock, onEditInput, onTestFlow, isRunning, onCancelTestFlow, onOpenPreview, onHideJobStatus, individualStepTests = false, job, showJobStatus = false, darkMode = false, flowHasChanged = false } = $props();
12
+ const outputPickerVisible = $derived((nodeKind || (inputJson && Object.keys(inputJson).length > 0)) && editMode);
12
13
  let action = $derived(label === 'Input' ? getAiModuleAction(label) : undefined);
14
+ let hoverButton = $state(false);
15
+ const outputType = $derived(showJobStatus
16
+ ? job?.type === 'QueuedJob'
17
+ ? 'InProgress'
18
+ : job?.type === 'CompletedJob'
19
+ ? job.success
20
+ ? 'Success'
21
+ : 'Failure'
22
+ : undefined
23
+ : undefined);
13
24
  </script>
14
25
 
15
26
  <VirtualItemWrapper
@@ -61,6 +72,8 @@ let action = $derived(label === 'Input' ? getAiModuleAction(label) : undefined);
61
72
  id={id ?? ''}
62
73
  isConnectingCandidate={true}
63
74
  variant="virtual"
75
+ type={outputType}
76
+ {darkMode}
64
77
  >
65
78
  {#snippet children({ allowCopy, isConnecting, selectConnection })}
66
79
  <OutputPickerInner
@@ -70,18 +83,25 @@ let action = $derived(label === 'Input' ? getAiModuleAction(label) : undefined);
70
83
  onSelect={selectConnection}
71
84
  moduleId={''}
72
85
  {onUpdateMock}
73
- hideHeaderBar
86
+ hideHeaderBar={nodeKind !== 'result'}
74
87
  simpleViewer={inputJson}
75
88
  rightMargin
76
89
  historyOffset={{ mainAxis: 12, crossAxis: -9 }}
77
90
  clazz="p-1"
78
91
  {onEditInput}
79
92
  selectionId={id ?? label ?? ''}
93
+ testJob={job}
94
+ disableMock
95
+ disableHistory
96
+ customEmptyJobMessage={nodeKind === 'result'
97
+ ? 'Test the flow to see results'
98
+ : undefined}
80
99
  />
81
100
  {/snippet}
82
101
  </OutputPicker>
83
102
  {/if}
84
103
  </div>
104
+
85
105
  <div class="absolute text-sm right-12 -bottom-3 flex flex-row gap-1 z-10">
86
106
  {#if cache}
87
107
  <Popover notClickable>
@@ -111,4 +131,36 @@ let action = $derived(label === 'Input' ? getAiModuleAction(label) : undefined);
111
131
  {/if}
112
132
  </div>
113
133
  {/snippet}
134
+ {#snippet previewButton()}
135
+ {#if nodeKind === 'input'}
136
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
137
+ <div
138
+ class="absolute top-1/2 -translate-y-[35px] -translate-x-[100%] -left-[0] flex py-4 justify-end w-fit px-2 min-w-32"
139
+ onmouseenter={() => {
140
+ hoverButton = true
141
+ }}
142
+ onmouseleave={() => {
143
+ hoverButton = false
144
+ }}
145
+ >
146
+ {#if outputPickerVisible}
147
+ <div transition:fade={{ duration: 100 }}>
148
+ <FlowGraphPreviewButton
149
+ {isRunning}
150
+ hover={hoverButton}
151
+ {selected}
152
+ {onTestFlow}
153
+ {onCancelTestFlow}
154
+ {onOpenPreview}
155
+ {onHideJobStatus}
156
+ {individualStepTests}
157
+ {job}
158
+ {showJobStatus}
159
+ {flowHasChanged}
160
+ />
161
+ </div>
162
+ {/if}
163
+ </div>
164
+ {/if}
165
+ {/snippet}
114
166
  </VirtualItemWrapper>
@@ -1,3 +1,4 @@
1
+ import type { Job } from '../../../gen';
1
2
  interface Props {
2
3
  label?: string | undefined;
3
4
  bgColor?: string;
@@ -11,7 +12,6 @@ interface Props {
11
12
  preLabel?: string | undefined;
12
13
  inputJson?: Object | undefined;
13
14
  prefix?: string;
14
- alwaysPluggable?: boolean;
15
15
  cache?: boolean;
16
16
  earlyStop?: boolean;
17
17
  editMode?: boolean;
@@ -21,6 +21,18 @@ interface Props {
21
21
  return_value?: unknown;
22
22
  }) => void;
23
23
  onEditInput?: (moduleId: string, key: string) => void;
24
+ onTestFlow?: () => void;
25
+ isRunning?: boolean;
26
+ onCancelTestFlow?: () => void;
27
+ onOpenPreview?: () => void;
28
+ onHideJobStatus?: () => void;
29
+ individualStepTests?: boolean;
30
+ nodeKind?: 'input' | 'result';
31
+ job?: Job;
32
+ type?: string;
33
+ showJobStatus?: boolean;
34
+ darkMode?: boolean;
35
+ flowHasChanged?: boolean;
24
36
  }
25
37
  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> {
26
38
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -1,40 +1,44 @@
1
1
  <script lang="ts">import { classNames } from '../../../utils';
2
2
  import { createEventDispatcher } from 'svelte';
3
3
  import { twMerge } from 'tailwind-merge';
4
- let { label, selectable, selected, id, onTop = false, bgColor, bgHoverColor = '', children, outputPickerVisible = false, className } = $props();
4
+ let { label, selectable, selected, id, onTop = false, bgColor, bgHoverColor = '', children, outputPickerVisible = false, className, previewButton } = $props();
5
5
  const dispatch = createEventDispatcher();
6
6
  let hover = $state(false);
7
7
  </script>
8
8
 
9
- <!-- svelte-ignore a11y_click_events_have_key_events -->
10
- <!-- svelte-ignore a11y_no_static_element_interactions -->
11
- <div
12
- class={classNames('w-full flex relative rounded-sm', onTop ? 'z-[901]' : '', className)}
13
- style="width: 275px; max-height: 34px; background-color: {hover && bgHoverColor && selectable
14
- ? bgHoverColor
15
- : bgColor};"
16
- onpointerdown={() => {
17
- if (selectable) {
18
- dispatch('select', id || label || '')
19
- }
20
- }}
21
- onmouseenter={() => {
22
- hover = true
23
- }}
24
- onmouseleave={() => {
25
- hover = false
26
- }}
27
- title={label ? label + ' ' : ''}
28
- id={`flow-editor-virtual-${encodeURIComponent(label || label || '')}`}
29
- >
9
+ <div class="relative">
10
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
11
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
30
12
  <div
31
- class={twMerge(
32
- 'absolute outline-gray-600 dark:outline-gray-400 rounded-sm',
33
- selected ? 'outline outline-2' : '',
34
- selectable ? 'cursor-pointer active:outline active:outline-2' : ''
35
- )}
36
- style={`width: 275px; height: ${outputPickerVisible ? '50px' : '34px'};`}
13
+ class={classNames('w-full flex relative rounded-sm', onTop ? 'z-[901]' : '', className)}
14
+ style="width: 275px; max-height: 34px; background-color: {hover && bgHoverColor && selectable
15
+ ? bgHoverColor
16
+ : bgColor};"
17
+ onpointerdown={() => {
18
+ if (selectable) {
19
+ dispatch('select', id || label || '')
20
+ }
21
+ }}
22
+ onmouseenter={() => {
23
+ hover = true
24
+ }}
25
+ onmouseleave={() => {
26
+ hover = false
27
+ }}
28
+ title={label ? label + ' ' : ''}
29
+ id={`flow-editor-virtual-${encodeURIComponent(label || label || '')}`}
37
30
  >
31
+ <div
32
+ class={twMerge(
33
+ 'absolute outline-gray-600 dark:outline-gray-400 rounded-sm',
34
+ selected ? 'outline outline-2' : '',
35
+ selectable ? 'cursor-pointer active:outline active:outline-2' : ''
36
+ )}
37
+ style={`width: 275px; height: ${outputPickerVisible ? '50px' : '34px'};`}
38
+ >
39
+ </div>
40
+ {@render children?.({ hover })}
38
41
  </div>
39
- {@render children?.({ hover })}
42
+
43
+ {@render previewButton?.()}
40
44
  </div>
@@ -10,6 +10,7 @@ interface Props {
10
10
  children?: import('svelte').Snippet<[any]>;
11
11
  outputPickerVisible?: boolean;
12
12
  className?: string;
13
+ previewButton?: import('svelte').Snippet;
13
14
  }
14
15
  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> {
15
16
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
@@ -1,11 +1,12 @@
1
1
  <script lang="ts">import Popover from '../../meltComponents/Popover.svelte';
2
2
  import { twMerge } from 'tailwind-merge';
3
- import { getContext } from 'svelte';
3
+ import { getContext, onMount } from 'svelte';
4
4
  import AnimatedButton from '../../common/button/AnimatedButton.svelte';
5
5
  import InputPickerInner from './InputPickerInner.svelte';
6
6
  import { ChevronDown, Plug } from 'lucide-svelte';
7
7
  import { useSvelteFlow } from '@xyflow/svelte';
8
- let { selected = false, hover = false, isConnectingCandidate = false, variant = 'default', historyOpen = false, children, inputTransform, id, bottomBarOpen = $bindable(false), loopStatus, onEditInput } = $props();
8
+ import { getStateColor } from '../../graph/util';
9
+ let { selected = false, hover = false, isConnectingCandidate = false, variant = 'default', historyOpen = false, children, inputTransform, id, bottomBarOpen = $bindable(false), loopStatus, onEditInput, type, darkMode, skipped } = $props();
9
10
  const context = getContext('PropPickerContext');
10
11
  const flowPropPickerConfig = context?.flowPropPickerConfig;
11
12
  const MIN_WIDTH = 375;
@@ -57,6 +58,17 @@ function updatePositioning(historyOpen, zoom) {
57
58
  $effect(() => {
58
59
  updatePositioning(historyOpen, zoom);
59
60
  });
61
+ onMount(() => {
62
+ let { outputPickerOpenFns } = getContext('FlowEditorContext') || {};
63
+ if (outputPickerOpenFns) {
64
+ outputPickerOpenFns[id] = () => {
65
+ outputOpen = true;
66
+ };
67
+ return () => {
68
+ delete outputPickerOpenFns[id];
69
+ };
70
+ }
71
+ });
60
72
  </script>
61
73
 
62
74
  <div
@@ -80,6 +92,9 @@ $effect(() => {
80
92
  'h-1 hover:h-[20px]',
81
93
  bottomBarOpen && 'h-[20px]'
82
94
  )}
95
+ style:background-color={type && type !== 'WaitingForEvents'
96
+ ? getStateColor(type, !!darkMode, true, skipped)
97
+ : undefined}
83
98
  data-prop-picker
84
99
  >
85
100
  <div class="flex flex-row items-center justify-center w-full h-full">
@@ -1,3 +1,4 @@
1
+ import type { FlowStatusModule } from '../../../gen';
1
2
  interface Props {
2
3
  selected?: boolean;
3
4
  hover?: boolean;
@@ -15,6 +16,9 @@ interface Props {
15
16
  onEditInput?: (moduleId: string, key: string) => void;
16
17
  initial?: boolean;
17
18
  onResetInitial?: () => void;
19
+ type: FlowStatusModule['type'] | undefined;
20
+ darkMode?: boolean;
21
+ skipped?: boolean;
18
22
  }
19
23
  declare const OutputPicker: import("svelte").Component<Props, {
20
24
  toggleOpen: (forceOpen?: boolean) => void;
@@ -27,7 +27,7 @@ import { twMerge } from 'tailwind-merge';
27
27
  import DisplayResultControlBar from '../../DisplayResultControlBar.svelte';
28
28
  import { base } from '../../../base';
29
29
  import { fade } from 'svelte/transition';
30
- let { lastJob = undefined, testJob = undefined, prefix = '', allowCopy = false, connectingData = undefined, mock = $bindable({ enabled: false }), moduleId = '', fullResult = false, closeOnOutsideClick = false, getLogs = false, selectedJob = $bindable(undefined), forceJson = $bindable(false), isLoading = $bindable(false), preview = $bindable(undefined), hideHeaderBar = false, simpleViewer = undefined, path = '', loopStatus = undefined, customHeight = undefined, rightMargin = false, disableMock = false, disableHistory = false, derivedHistoryOpen = $bindable(false), historyOffset = { mainAxis: 8, crossAxis: -4.5 }, clazz, copilot_fix, onSelect, onUpdateMock, onEditInput, selectionId, initial } = $props();
30
+ let { lastJob = undefined, testJob = undefined, prefix = '', allowCopy = false, connectingData = undefined, mock = $bindable({ enabled: false }), moduleId = '', fullResult = false, closeOnOutsideClick = false, getLogs = false, selectedJob = $bindable(undefined), forceJson = $bindable(false), isLoading = $bindable(false), preview = $bindable(undefined), hideHeaderBar = false, simpleViewer = undefined, path = '', loopStatus = undefined, customHeight = undefined, rightMargin = false, disableMock = false, disableHistory = false, derivedHistoryOpen = $bindable(false), historyOffset = { mainAxis: 8, crossAxis: -4.5 }, clazz, copilot_fix, onSelect, onUpdateMock, onEditInput, selectionId, initial, customEmptyJobMessage } = $props();
31
31
  let jsonView = $state(false);
32
32
  let clientHeight = $state(0);
33
33
  let tmpMock = $state(undefined);
@@ -601,7 +601,7 @@ const copilot_fix_render = $derived(copilot_fix);
601
601
  {:else if !job}
602
602
  <div class="flex flex-col items-center justify-center h-full">
603
603
  <p class="text-xs text-secondary">
604
- Test this step to see results{#if !disableMock}
604
+ {customEmptyJobMessage ?? 'Test this step to see results'}{#if !disableMock}
605
605
  {' or'}
606
606
  <button
607
607
  class="text-blue-500 hover:text-blue-700 underline"
@@ -50,6 +50,7 @@ interface Props {
50
50
  selectionId?: string;
51
51
  initial?: boolean;
52
52
  onResetInitial?: () => void;
53
+ customEmptyJobMessage?: string;
53
54
  }
54
55
  declare const OutputPickerInner: import("svelte").Component<Props, {}, "preview" | "isLoading" | "mock" | "forceJson" | "selectedJob" | "derivedHistoryOpen">;
55
56
  type OutputPickerInner = ReturnType<typeof OutputPickerInner>;
@@ -8,6 +8,7 @@ import type Editor from '../Editor.svelte';
8
8
  import type SimpleEditor from '../SimpleEditor.svelte';
9
9
  import type { StateStore } from '../../utils';
10
10
  import type { TestSteps } from './testSteps.svelte';
11
+ import type { ModulesTestStates } from '../modulesTest.svelte';
11
12
  export type FlowInput = Record<string, {
12
13
  flowStepWarnings?: Record<string, {
13
14
  message: string;
@@ -60,4 +61,6 @@ export type FlowEditorContext = {
60
61
  customUi: FlowBuilderWhitelabelCustomUi;
61
62
  insertButtonOpen: Writable<boolean>;
62
63
  executionCount: Writable<number>;
64
+ modulesTestStates: ModulesTestStates;
65
+ outputPickerOpenFns: Record<string, () => void>;
63
66
  };
@@ -1,7 +1,10 @@
1
1
  import { type FlowModule, type Job, type RestartedFrom, type OpenFlow } from '../../gen';
2
+ import { type Writable } from 'svelte/store';
2
3
  import type { FlowModuleState } from './flowState';
3
4
  import { type PickableProperties } from './previousResults';
4
5
  import type { ExtendedOpenFlow } from './types';
6
+ import type { GraphModuleState } from '../graph';
7
+ import type { ModulesTestStates } from '../modulesTest.svelte';
5
8
  export type ModuleArgs = {
6
9
  value: Record<string, any>;
7
10
  };
@@ -32,3 +35,9 @@ export declare function checkIfParentLoop(flowStore: ExtendedOpenFlow, modId: st
32
35
  id: string;
33
36
  type: 'forloopflow' | 'whileloopflow';
34
37
  } | undefined;
38
+ /**
39
+ * Updates moduleStates based on test job data from modulesTestStates
40
+ * Extracts job information and converts it to GraphModuleState format
41
+ * for graph rendering
42
+ */
43
+ export declare function updateDerivedModuleStatesFromTestJobs(moduleId: string | undefined, moduleTestStates: ModulesTestStates | undefined, moduleStates: Writable<Record<string, GraphModuleState>> | undefined): void;
@@ -148,3 +148,42 @@ export function checkIfParentLoop(flowStore, modId) {
148
148
  }
149
149
  return undefined;
150
150
  }
151
+ /**
152
+ * Updates moduleStates based on test job data from modulesTestStates
153
+ * Extracts job information and converts it to GraphModuleState format
154
+ * for graph rendering
155
+ */
156
+ export function updateDerivedModuleStatesFromTestJobs(moduleId, moduleTestStates, moduleStates) {
157
+ if (!moduleId || !moduleTestStates || !moduleStates) {
158
+ return;
159
+ }
160
+ const newStates = {};
161
+ const testState = moduleTestStates?.states[moduleId];
162
+ if (testState) {
163
+ if (testState.testJob) {
164
+ const job = testState.testJob;
165
+ // Create GraphModuleState from job data
166
+ const moduleState = {
167
+ args: job.args,
168
+ type: job.type === 'QueuedJob' ? 'InProgress' : job['success'] ? 'Success' : 'Failure',
169
+ job_id: job.id,
170
+ tag: job.tag,
171
+ duration_ms: job['duration_ms'],
172
+ started_at: job.started_at ? new Date(job.started_at).getTime() : undefined
173
+ };
174
+ newStates[moduleId] = moduleState;
175
+ }
176
+ else if (testState.loading) {
177
+ // If test is loading, show as InProgress
178
+ newStates[moduleId] = {
179
+ type: 'InProgress',
180
+ args: {}
181
+ };
182
+ }
183
+ }
184
+ // Update the store with test job states
185
+ moduleStates.update((currentStates) => ({
186
+ ...currentStates,
187
+ ...newStates
188
+ }));
189
+ }
@@ -36,7 +36,7 @@ const triggerContext = getContext('TriggerContext');
36
36
  let fullWidth = 0;
37
37
  let width = $state(0);
38
38
  let simplifiableFlow = $state(undefined);
39
- let { onInsert = undefined, onDelete = undefined, onMove = undefined, onDeleteBranch = undefined, onNewBranch = undefined, onSelect = undefined, onChangeId = undefined, onUpdateMock = undefined, onSelectedIteration = undefined, success = undefined, modules = [], failureModule = undefined, preprocessorModule = undefined, minHeight = 0, maxHeight = undefined, notSelectable = false, flowModuleStates = undefined, selectedId = writable(undefined), path = undefined, newFlow = false, insertable = false, earlyStop = false, cache = false, scroll = false, moving = undefined, download = false, fullSize = false, disableAi = false, triggerNode = false, workspace = $workspaceStore ?? 'NO_WORKSPACE', editMode = false, allowSimplifiedPoll = true, expandedSubflows = $bindable({}), onTestUpTo = undefined, onEditInput = undefined } = $props();
39
+ let { onInsert = undefined, onDelete = undefined, onMove = undefined, onDeleteBranch = undefined, onNewBranch = undefined, onSelect = undefined, onChangeId = undefined, onUpdateMock = undefined, onSelectedIteration = undefined, success = undefined, modules = [], failureModule = undefined, preprocessorModule = undefined, minHeight = 0, maxHeight = undefined, notSelectable = false, flowModuleStates = undefined, selectedId = writable(undefined), path = undefined, newFlow = false, insertable = false, earlyStop = false, cache = false, scroll = false, moving = undefined, download = false, fullSize = false, disableAi = false, triggerNode = false, workspace = $workspaceStore ?? 'NO_WORKSPACE', editMode = false, allowSimplifiedPoll = true, expandedSubflows = $bindable({}), onTestUpTo = undefined, onEditInput = undefined, isOwner = false, onTestFlow = undefined, isRunning = false, onCancelTestFlow = undefined, onOpenPreview = undefined, onHideJobStatus = undefined, individualStepTests = false, flowJob = undefined, showJobStatus = false, suspendStatus = writable({}), flowHasChanged = false } = $props();
40
40
  setContext('FlowGraphContext', { selectedId, useDataflow });
41
41
  if (triggerContext && allowSimplifiedPoll) {
42
42
  if (isSimplifiable(modules)) {
@@ -179,6 +179,18 @@ let eventHandler = {
179
179
  },
180
180
  editInput: (moduleId, key) => {
181
181
  onEditInput?.(moduleId, key);
182
+ },
183
+ testFlow: () => {
184
+ onTestFlow?.();
185
+ },
186
+ cancelTestFlow: () => {
187
+ onCancelTestFlow?.();
188
+ },
189
+ openPreview: () => {
190
+ onOpenPreview?.();
191
+ },
192
+ hideJobStatus: () => {
193
+ onHideJobStatus?.();
182
194
  }
183
195
  };
184
196
  let lastModules = structuredClone($state.snapshot(modules));
@@ -257,7 +269,14 @@ let graph = $derived.by(() => {
257
269
  newFlow,
258
270
  cache,
259
271
  earlyStop,
260
- editMode
272
+ editMode,
273
+ isOwner,
274
+ isRunning,
275
+ individualStepTests,
276
+ flowJob,
277
+ showJobStatus,
278
+ suspendStatus,
279
+ flowHasChanged
261
280
  }, failureModule, preprocessorModule, eventHandler, success, $useDataflow, $selectedId, moving, simplifiableFlow, triggerNode ? path : undefined, expandedSubflows);
262
281
  });
263
282
  $effect(() => {
@@ -290,6 +309,10 @@ $effect(() => {
290
309
  }
291
310
  }, 10);
292
311
  });
312
+ let viewportResizer = $state(undefined);
313
+ export function isNodeVisible(nodeId) {
314
+ return viewportResizer?.isNodeVisible(nodeId) ?? false;
315
+ }
293
316
  </script>
294
317
 
295
318
  {#if insertable}
@@ -312,7 +335,7 @@ $effect(() => {
312
335
  </div>
313
336
  {:else}
314
337
  <SvelteFlowProvider>
315
- <ViewportResizer {width} />
338
+ <ViewportResizer {height} {width} {nodes} bind:this={viewportResizer} />
316
339
  <SvelteFlow
317
340
  onpaneclick={(e) => {
318
341
  document.dispatchEvent(new Event('focus'))
@@ -334,7 +357,7 @@ $effect(() => {
334
357
  nodesDraggable={false}
335
358
  --background-color={false}
336
359
  >
337
- <div class="absolute inset-0 !bg-surface-secondary"></div>
360
+ <div class="absolute inset-0 !bg-surface-secondary h-full"></div>
338
361
  <Controls position="top-right" orientation="horizontal" showLock={false}>
339
362
  {#if download}
340
363
  <ControlButton