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
@@ -1,6 +1,9 @@
1
1
  <script lang="ts">import AppEditor from './apps/editor/AppEditor.svelte';
2
2
  let { app: oldApp, ...props } = $props();
3
3
  let app = $state(oldApp);
4
+ $effect(() => {
5
+ app = oldApp;
6
+ });
4
7
  </script>
5
8
 
6
9
  <AppEditor {app} {...props} />
@@ -28,6 +28,8 @@ import Tooltip from './Tooltip.svelte';
28
28
  import { workspaceAIClients } from './copilot/lib';
29
29
  import { Triggers } from './triggers/triggers.svelte';
30
30
  import { TestSteps } from './flows/testSteps.svelte';
31
+ import { ModulesTestStates } from './modulesTest.svelte';
32
+ import { updateDerivedModuleStatesFromTestJobs } from './flows/utils';
31
33
  let flowCopilotContext = {
32
34
  shouldUpdatePropertyType: writable({}),
33
35
  exprsToSet: writable({}),
@@ -74,6 +76,11 @@ let testIsLoading = $state(false);
74
76
  let testJob = $state();
75
77
  let pastPreviews = $state([]);
76
78
  let validCode = $state(true);
79
+ // Flow preview
80
+ let flowPreviewButtons = $state();
81
+ const job = $derived(flowPreviewButtons?.getJob());
82
+ let showJobStatus = $state(false);
83
+ let testModuleId = $state(undefined);
77
84
  let currentScript = $state(undefined);
78
85
  let schema = $state(emptySchema());
79
86
  const href = window.location.href;
@@ -363,6 +370,13 @@ const history = initHistory(flowStore.val);
363
370
  const testSteps = new TestSteps();
364
371
  const selectedIdStore = writable('settings-metadata');
365
372
  const triggersCount = writable(undefined);
373
+ const modulesTestStates = new ModulesTestStates((moduleId) => {
374
+ // Update the derived store with test job states
375
+ delete $derivedModuleStates[moduleId];
376
+ testModuleId = moduleId;
377
+ showJobStatus = false;
378
+ });
379
+ const outputPickerOpenFns = $state({});
366
380
  setContext('TriggerContext', {
367
381
  triggersCount: triggersCount,
368
382
  simplifiedPoll: writable(false),
@@ -391,7 +405,9 @@ setContext('FlowEditorContext', {
391
405
  editPanelSize: undefined,
392
406
  payloadData: undefined
393
407
  }),
394
- currentEditor: writable(undefined)
408
+ currentEditor: writable(undefined),
409
+ modulesTestStates,
410
+ outputPickerOpenFns
395
411
  });
396
412
  setContext('PropPickerContext', {
397
413
  flowPropPickerConfig: writable(undefined),
@@ -407,7 +423,6 @@ function updateFlow(flow) {
407
423
  window?.parent.postMessage({ type: 'flow', flow, uriPath: lastUriPath }, '*');
408
424
  }
409
425
  }
410
- let flowPreviewButtons = $state();
411
426
  let reload = $state(0);
412
427
  async function inferModuleArgs(selectedIdStore) {
413
428
  if (selectedIdStore == '') {
@@ -471,6 +486,53 @@ $effect(() => {
471
486
  $effect(() => {
472
487
  $selectedIdStore && untrack(() => inferModuleArgs($selectedIdStore));
473
488
  });
489
+ const localModuleStates = $derived(flowPreviewButtons?.getLocalModuleStates() ?? writable({}));
490
+ const localDurationStatuses = $derived(flowPreviewButtons?.getLocalDurationStatuses() ?? writable({}));
491
+ const suspendStatus = $derived(flowPreviewButtons?.getSuspendStatus() ?? writable({}));
492
+ // Create a derived store that only shows the module states when showModuleStatus is true
493
+ // this store can also be updated
494
+ let derivedModuleStates = writable({});
495
+ $effect(() => {
496
+ derivedModuleStates.update((currentStates) => {
497
+ return showJobStatus ? $localModuleStates : currentStates;
498
+ });
499
+ });
500
+ $effect(() => {
501
+ updateDerivedModuleStatesFromTestJobs(testModuleId, modulesTestStates, derivedModuleStates);
502
+ });
503
+ let flowModuleSchemaMap = $state();
504
+ function onJobDone() {
505
+ if (!job) {
506
+ return;
507
+ }
508
+ // job was running and is now stopped
509
+ if (!flowPreviewButtons?.getPreviewOpen()) {
510
+ if (job.type === 'CompletedJob' &&
511
+ job.success &&
512
+ flowPreviewButtons?.getPreviewMode() === 'whole') {
513
+ if (flowModuleSchemaMap?.isNodeVisible('result') && $selectedIdStore !== 'Result') {
514
+ outputPickerOpenFns['Result']?.();
515
+ }
516
+ }
517
+ else {
518
+ // Find last module with a job in flow_status
519
+ const lastModuleWithJob = job.flow_status?.modules
520
+ ?.slice()
521
+ .reverse()
522
+ .find((module) => 'job' in module);
523
+ if (lastModuleWithJob &&
524
+ lastModuleWithJob.id &&
525
+ flowModuleSchemaMap?.isNodeVisible(lastModuleWithJob.id)) {
526
+ outputPickerOpenFns[lastModuleWithJob.id]?.();
527
+ }
528
+ }
529
+ }
530
+ }
531
+ function resetModulesStates() {
532
+ derivedModuleStates.set({});
533
+ showJobStatus = false;
534
+ }
535
+ const individualStepTests = $derived(!(showJobStatus && job) && Object.keys($derivedModuleStates).length > 0);
474
536
  </script>
475
537
 
476
538
  <svelte:window onkeydown={onKeyDown} />
@@ -608,18 +670,40 @@ $effect(() => {
608
670
  {/if}
609
671
  </div>
610
672
 
611
- <div class="flex justify-center pt-1 z-50 absolute right-2 top-2 gap-2">
612
- <FlowPreviewButtons bind:this={flowPreviewButtons} />
673
+ <div class="flex justify-center pt-1 z-50 absolute -translate-x-[100%] right-2 top-2 gap-2">
674
+ <FlowPreviewButtons
675
+ bind:this={flowPreviewButtons}
676
+ {onJobDone}
677
+ onRunPreview={() => {
678
+ localModuleStates.set({})
679
+ showJobStatus = true
680
+ }}
681
+ />
613
682
  </div>
614
683
  <Splitpanes horizontal class="h-full max-h-screen grow">
615
684
  <Pane size={67}>
616
685
  {#if flowStore.val?.value?.modules}
617
686
  <div id="flow-editor"></div>
618
687
  <FlowModuleSchemaMap
688
+ bind:this={flowModuleSchemaMap}
619
689
  disableAi
620
690
  disableTutorials
621
691
  smallErrorHandler={true}
622
692
  disableStaticInputs
693
+ localModuleStates={derivedModuleStates}
694
+ onTestUpTo={flowPreviewButtons?.testUpTo}
695
+ isOwner={flowPreviewButtons?.getIsOwner()}
696
+ onTestFlow={flowPreviewButtons?.runPreview}
697
+ isRunning={flowPreviewButtons?.getIsRunning()}
698
+ onCancelTestFlow={flowPreviewButtons?.cancelTest}
699
+ onOpenPreview={flowPreviewButtons?.openPreview}
700
+ onHideJobStatus={resetModulesStates}
701
+ {individualStepTests}
702
+ flowJob={job}
703
+ {showJobStatus}
704
+ onDelete={(id) => {
705
+ delete $derivedModuleStates[id]
706
+ }}
623
707
  />
624
708
  {:else}
625
709
  <div class="text-red-400 mt-20">Missing flow modules</div>
@@ -639,6 +723,12 @@ $effect(() => {
639
723
  flowPreviewButtons?.openPreview()
640
724
  }
641
725
  }}
726
+ onTestFlow={flowPreviewButtons?.runPreview}
727
+ {job}
728
+ isOwner={flowPreviewButtons?.getIsOwner()}
729
+ {localDurationStatuses}
730
+ {suspendStatus}
731
+ onOpenDetails={flowPreviewButtons?.openPreview}
642
732
  />
643
733
  {/key}
644
734
  </Pane>
@@ -15,7 +15,7 @@ import ScriptEditorDrawer from './flows/content/ScriptEditorDrawer.svelte';
15
15
  import { dfs as dfsApply } from './flows/dfs';
16
16
  import FlowImportExportMenu from './flows/header/FlowImportExportMenu.svelte';
17
17
  import FlowPreviewButtons from './flows/header/FlowPreviewButtons.svelte';
18
- import { cleanInputs } from './flows/utils';
18
+ import { cleanInputs, updateDerivedModuleStatesFromTestJobs } from './flows/utils';
19
19
  import { Calendar, Pen, Save, DiffIcon, HistoryIcon, FileJson, Settings } from 'lucide-svelte';
20
20
  import Awareness from './Awareness.svelte';
21
21
  import { getAllModules } from './flows/flowExplorer';
@@ -36,6 +36,7 @@ import { Triggers } from './triggers/triggers.svelte';
36
36
  import { TestSteps } from './flows/testSteps.svelte';
37
37
  import { aiChatManager } from './copilot/chat/AIChatManager.svelte';
38
38
  import { setStepHistoryLoaderContext, StepHistoryLoader } from './stepHistoryLoader.svelte';
39
+ import { ModulesTestStates } from './modulesTest.svelte';
39
40
  let { initialPath = $bindable(''), pathStoreInit = undefined, newFlow, selectedId, initialArgs = {}, loading = false, flowStore, flowStateStore, savedFlow = $bindable(undefined), diffDrawer = undefined, customUi = {}, disableAi = false, disabledFlowInputs = false, savedPrimarySchedule = undefined, version = undefined, setSavedraftCb = undefined, draftTriggersFromUrl = undefined, selectedTriggerIndexFromUrl = undefined, children, loadedFromHistoryFromUrl, noInitial = false, onSaveInitial, onSaveDraft, onDeploy, onDeployError, onDetails, onSaveDraftError, onSaveDraftOnlyAtNewPath, onHistoryRestore } = $props();
40
41
  let initialPathStore = writable(initialPath);
41
42
  // used for new flows for captures
@@ -56,6 +57,11 @@ let confirmDeploymentCallback = () => { };
56
57
  // AI changes warning modal
57
58
  let aiChangesWarningOpen = $state(false);
58
59
  let aiChangesConfirmCallback = $state(() => { });
60
+ // Flow preview
61
+ let flowPreviewButtons = $state();
62
+ const flowPreviewContent = $derived(flowPreviewButtons?.getFlowPreviewContent());
63
+ const job = $derived(flowPreviewContent?.getJob());
64
+ let showJobStatus = $state(false);
59
65
  async function handleDraftTriggersConfirmed(event) {
60
66
  const { selectedTriggers } = event.detail;
61
67
  // Continue with saving the flow
@@ -438,6 +444,15 @@ function select(selectedId) {
438
444
  selectedIdStore.set(selectedId);
439
445
  }
440
446
  let insertButtonOpen = writable(false);
447
+ let testModuleId = $state(undefined);
448
+ let modulesTestStates = new ModulesTestStates((moduleId) => {
449
+ // Update the derived store with test job states
450
+ delete $derivedModuleStates[moduleId];
451
+ testModuleId = moduleId;
452
+ showJobStatus = false;
453
+ });
454
+ let outputPickerOpenFns = $state({});
455
+ let flowEditor = $state(undefined);
441
456
  setContext('FlowEditorContext', {
442
457
  selectedId: selectedIdStore,
443
458
  currentEditor: writable(undefined),
@@ -456,7 +471,9 @@ setContext('FlowEditorContext', {
456
471
  customUi,
457
472
  insertButtonOpen,
458
473
  executionCount: writable(0),
459
- flowInputEditorState: flowInputEditorStateStore
474
+ flowInputEditorState: flowInputEditorStateStore,
475
+ modulesTestStates,
476
+ outputPickerOpenFns
460
477
  });
461
478
  // Add triggers context store
462
479
  const triggersState = $state(new Triggers([
@@ -630,7 +647,6 @@ function handleDeployTrigger(trigger) {
630
647
  newSavedDraftTrigers.length > 0 ? newSavedDraftTrigers : undefined;
631
648
  }
632
649
  }
633
- let flowPreviewButtons = $state();
634
650
  let forceTestTab = $state({});
635
651
  let highlightArg = $state({});
636
652
  $effect.pre(() => {
@@ -670,6 +686,53 @@ export function setLoadedFromHistory(loadedFromHistoryUrl) {
670
686
  stepHistoryLoader.setFlowJobInitial(loadedFromHistoryUrl.flowJobInitial);
671
687
  stepHistoryLoader.stepStates = loadedFromHistoryUrl.stepsState;
672
688
  }
689
+ function onJobDone() {
690
+ if (!job) {
691
+ return;
692
+ }
693
+ // job was running and is now stopped
694
+ if (!flowPreviewButtons?.getPreviewOpen()) {
695
+ if (job.type === 'CompletedJob' &&
696
+ job.success &&
697
+ flowPreviewButtons?.getPreviewMode() === 'whole') {
698
+ if (flowEditor?.isNodeVisible('result') && $selectedIdStore !== 'Result') {
699
+ outputPickerOpenFns['Result']?.();
700
+ }
701
+ }
702
+ else {
703
+ // Find last module with a job in flow_status
704
+ const lastModuleWithJob = job.flow_status?.modules
705
+ ?.slice()
706
+ .reverse()
707
+ .find((module) => 'job' in module);
708
+ if (lastModuleWithJob &&
709
+ lastModuleWithJob.id &&
710
+ flowEditor?.isNodeVisible(lastModuleWithJob.id)) {
711
+ outputPickerOpenFns[lastModuleWithJob.id]?.();
712
+ }
713
+ }
714
+ }
715
+ }
716
+ const localModuleStates = $derived(flowPreviewContent?.getLocalModuleStates() ?? writable({}));
717
+ const localDurationStatuses = $derived(flowPreviewContent?.getLocalDurationStatuses() ?? writable({}));
718
+ const suspendStatus = $derived(flowPreviewContent?.getSuspendStatus() ?? writable({}));
719
+ // Create a derived store that only shows the module states when showModuleStatus is true
720
+ // this store can also be updated
721
+ let derivedModuleStates = writable({});
722
+ $effect(() => {
723
+ derivedModuleStates.update((currentStates) => {
724
+ return showJobStatus ? $localModuleStates : currentStates;
725
+ });
726
+ });
727
+ $effect(() => {
728
+ updateDerivedModuleStatesFromTestJobs(testModuleId, modulesTestStates, derivedModuleStates);
729
+ });
730
+ function resetModulesStates() {
731
+ derivedModuleStates.set({});
732
+ showJobStatus = false;
733
+ }
734
+ const individualStepTests = $derived(!(showJobStatus && job) && Object.keys($derivedModuleStates).length > 0);
735
+ const flowHasChanged = $derived(flowPreviewContent?.flowHasChanged());
673
736
  </script>
674
737
 
675
738
  <svelte:window onkeydown={onKeyDown} />
@@ -862,8 +925,13 @@ export function setLoadedFromHistory(loadedFromHistoryUrl) {
862
925
  captureOn.set(true)
863
926
  showCaptureHint.set(true)
864
927
  }}
928
+ {onJobDone}
865
929
  bind:this={flowPreviewButtons}
866
930
  {loading}
931
+ onRunPreview={() => {
932
+ localModuleStates.set({})
933
+ showJobStatus = true
934
+ }}
867
935
  />
868
936
  <Button
869
937
  loading={loadingDraft}
@@ -890,6 +958,7 @@ export function setLoadedFromHistory(loadedFromHistoryUrl) {
890
958
  <!-- metadata -->
891
959
  {#if $flowStateStore}
892
960
  <FlowEditor
961
+ bind:this={flowEditor}
893
962
  {disabledFlowInputs}
894
963
  disableAi={disableAi || customUi?.stepInputs?.ai == false}
895
964
  disableSettings={customUi?.settingsPanel === false}
@@ -908,8 +977,8 @@ export function setLoadedFromHistory(loadedFromHistoryUrl) {
908
977
  previewArgsStore.val = JSON.parse(JSON.stringify(e.detail))
909
978
  flowPreviewButtons?.openPreview(true)
910
979
  }}
911
- onTestUpTo={() => {
912
- flowPreviewButtons?.testUpTo()
980
+ onTestUpTo={(id) => {
981
+ flowPreviewButtons?.testUpTo(id)
913
982
  }}
914
983
  {savedFlow}
915
984
  onDeployTrigger={handleDeployTrigger}
@@ -929,9 +998,22 @@ export function setLoadedFromHistory(loadedFromHistoryUrl) {
929
998
  aiChatOpen={aiChatManager.open}
930
999
  showFlowAiButton={!disableAi && customUi?.topBar?.aiBuilder != false}
931
1000
  toggleAiChat={() => aiChatManager.toggleOpen()}
932
- onRunPreview={() => {
933
- flowPreviewButtons?.openPreview(true)
1001
+ onOpenPreview={flowPreviewButtons?.openPreview}
1002
+ localModuleStates={derivedModuleStates}
1003
+ isOwner={flowPreviewContent?.getIsOwner()}
1004
+ onTestFlow={flowPreviewButtons?.runPreview}
1005
+ isRunning={flowPreviewContent?.getIsRunning()}
1006
+ onCancelTestFlow={flowPreviewContent?.cancelTest}
1007
+ onHideJobStatus={resetModulesStates}
1008
+ {individualStepTests}
1009
+ {job}
1010
+ {localDurationStatuses}
1011
+ {suspendStatus}
1012
+ {showJobStatus}
1013
+ onDelete={(id) => {
1014
+ delete $derivedModuleStates[id]
934
1015
  }}
1016
+ {flowHasChanged}
935
1017
  />
936
1018
  {:else}
937
1019
  <CenteredPage>Loading...</CenteredPage>