@d34dman/flowdrop 0.0.43 → 0.0.44

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 (95) hide show
  1. package/README.md +8 -8
  2. package/dist/api/enhanced-client.d.ts +3 -1
  3. package/dist/api/enhanced-client.js +35 -5
  4. package/dist/components/App.svelte +68 -34
  5. package/dist/components/ConfigForm.svelte +169 -142
  6. package/dist/components/ConfigForm.svelte.d.ts +4 -2
  7. package/dist/components/ConfigPanel.svelte +42 -15
  8. package/dist/components/LogsSidebar.svelte +20 -19
  9. package/dist/components/Navbar.svelte +150 -80
  10. package/dist/components/Navbar.svelte.d.ts +8 -0
  11. package/dist/components/NodeSidebar.svelte +330 -217
  12. package/dist/components/PipelineStatus.svelte +6 -1
  13. package/dist/components/ReadOnlyDetails.svelte +14 -14
  14. package/dist/components/SchemaForm.svelte +49 -30
  15. package/dist/components/SchemaForm.svelte.d.ts +11 -1
  16. package/dist/components/SettingsModal.svelte +279 -0
  17. package/dist/components/SettingsModal.svelte.d.ts +23 -0
  18. package/dist/components/SettingsPanel.svelte +615 -0
  19. package/dist/components/SettingsPanel.svelte.d.ts +21 -0
  20. package/dist/components/ThemeToggle.svelte +186 -0
  21. package/dist/components/ThemeToggle.svelte.d.ts +14 -0
  22. package/dist/components/WorkflowEditor.svelte +110 -36
  23. package/dist/components/form/FormArray.svelte +81 -81
  24. package/dist/components/form/FormAutocomplete.svelte +1014 -0
  25. package/dist/components/form/FormAutocomplete.svelte.d.ts +25 -0
  26. package/dist/components/form/FormCheckboxGroup.svelte +16 -16
  27. package/dist/components/form/FormCodeEditor.svelte +26 -26
  28. package/dist/components/form/FormField.svelte +52 -21
  29. package/dist/components/form/FormFieldLight.svelte +19 -19
  30. package/dist/components/form/FormFieldWrapper.svelte +4 -4
  31. package/dist/components/form/FormMarkdownEditor.svelte +124 -57
  32. package/dist/components/form/FormNumberField.svelte +13 -13
  33. package/dist/components/form/FormRangeField.svelte +16 -16
  34. package/dist/components/form/FormSelect.svelte +15 -15
  35. package/dist/components/form/FormTemplateEditor.svelte +34 -34
  36. package/dist/components/form/FormTextField.svelte +13 -13
  37. package/dist/components/form/FormTextarea.svelte +13 -13
  38. package/dist/components/form/FormToggle.svelte +8 -8
  39. package/dist/components/form/index.d.ts +1 -0
  40. package/dist/components/form/index.js +1 -0
  41. package/dist/components/form/types.d.ts +133 -8
  42. package/dist/components/form/types.js +50 -1
  43. package/dist/components/interrupt/ChoicePrompt.svelte +45 -38
  44. package/dist/components/interrupt/ConfirmationPrompt.svelte +35 -35
  45. package/dist/components/interrupt/FormPrompt.svelte +27 -20
  46. package/dist/components/interrupt/InterruptBubble.svelte +50 -50
  47. package/dist/components/interrupt/TextInputPrompt.svelte +39 -32
  48. package/dist/components/layouts/MainLayout.svelte +233 -34
  49. package/dist/components/layouts/MainLayout.svelte.d.ts +12 -0
  50. package/dist/components/nodes/GatewayNode.svelte +102 -73
  51. package/dist/components/nodes/IdeaNode.svelte +53 -52
  52. package/dist/components/nodes/NotesNode.svelte +120 -88
  53. package/dist/components/nodes/SimpleNode.svelte +67 -47
  54. package/dist/components/nodes/SquareNode.svelte +86 -49
  55. package/dist/components/nodes/TerminalNode.svelte +122 -72
  56. package/dist/components/nodes/ToolNode.svelte +96 -65
  57. package/dist/components/nodes/WorkflowNode.svelte +91 -67
  58. package/dist/components/playground/ChatPanel.svelte +76 -76
  59. package/dist/components/playground/ExecutionLogs.svelte +71 -69
  60. package/dist/components/playground/InputCollector.svelte +59 -59
  61. package/dist/components/playground/MessageBubble.svelte +111 -112
  62. package/dist/components/playground/Playground.svelte +184 -138
  63. package/dist/components/playground/PlaygroundModal.svelte +18 -19
  64. package/dist/components/playground/SessionManager.svelte +68 -67
  65. package/dist/config/defaultPortConfig.js +22 -22
  66. package/dist/core/index.d.ts +2 -0
  67. package/dist/core/index.js +1 -0
  68. package/dist/form/fieldRegistry.d.ts +17 -1
  69. package/dist/form/fieldRegistry.js +18 -2
  70. package/dist/form/index.d.ts +20 -2
  71. package/dist/form/index.js +19 -1
  72. package/dist/helpers/workflowEditorHelper.js +23 -11
  73. package/dist/index.d.ts +5 -0
  74. package/dist/index.js +13 -0
  75. package/dist/services/autoSaveService.d.ts +112 -0
  76. package/dist/services/autoSaveService.js +223 -0
  77. package/dist/services/settingsService.d.ts +92 -0
  78. package/dist/services/settingsService.js +202 -0
  79. package/dist/services/toastService.d.ts +9 -0
  80. package/dist/services/toastService.js +30 -1
  81. package/dist/stores/settingsStore.d.ts +128 -0
  82. package/dist/stores/settingsStore.js +488 -0
  83. package/dist/stores/themeStore.d.ts +68 -0
  84. package/dist/stores/themeStore.js +215 -0
  85. package/dist/styles/base.css +298 -621
  86. package/dist/styles/toast.css +33 -0
  87. package/dist/styles/tokens.css +366 -0
  88. package/dist/types/index.d.ts +78 -0
  89. package/dist/types/index.js +2 -0
  90. package/dist/types/playground.d.ts +12 -0
  91. package/dist/types/settings.d.ts +185 -0
  92. package/dist/types/settings.js +101 -0
  93. package/dist/utils/colors.d.ts +100 -7
  94. package/dist/utils/colors.js +228 -67
  95. package/package.json +3 -3
package/README.md CHANGED
@@ -66,8 +66,8 @@ You get a production-ready workflow UI. You keep full control of everything else
66
66
 
67
67
  ## Features
68
68
 
69
- | | |
70
- | ---------------------------- | ------------------------------------------------------------------------- |
69
+ | | |
70
+ | --------------------------- | ------------------------------------------------------------------------- |
71
71
  | 🎨 **Visual Editor Only** | Pure UI component. No hidden backend, no external dependencies |
72
72
  | 🔐 **You Own Everything** | Your data, your servers, your orchestration logic, your security policies |
73
73
  | 🔌 **Backend Agnostic** | Connect to any API: Drupal, Laravel, Express, FastAPI, or your own |
@@ -214,12 +214,12 @@ Runtime configuration means you build once and deploy to staging, production, or
214
214
 
215
215
  ## Documentation
216
216
 
217
- | Resource | Description |
218
- | ---------------------------------- | ------------------------ |
219
- | [API.md](./API.md) | REST API specification |
220
- | [DOCKER.md](./DOCKER.md) | Docker deployment guide |
221
- | [QUICK_START.md](./QUICK_START.md) | Get running in 5 minutes |
222
- | [CHANGELOG.md](./CHANGELOG.md) | Version history |
217
+ | Resource | Description |
218
+ | ------------------------------------------------------------ | ------------------------ |
219
+ | [API Documentation](https://flowdrop-io.github.io/flowdrop/) | REST API specification |
220
+ | [DOCKER.md](./DOCKER.md) | Docker deployment guide |
221
+ | [QUICK_START.md](./QUICK_START.md) | Get running in 5 minutes |
222
+ | [CHANGELOG.md](./CHANGELOG.md) | Version history |
223
223
 
224
224
  ## Development
225
225
 
@@ -45,7 +45,9 @@ export declare class EnhancedFlowDropApiClient {
45
45
  */
46
46
  constructor(config: EndpointConfig, authProvider?: AuthProvider);
47
47
  /**
48
- * Make HTTP request with error handling, retry logic, and auth support
48
+ * Make HTTP request with error handling, retry logic, timeout, and auth support
49
+ *
50
+ * Uses apiSettings for timeout and retry configuration, falling back to EndpointConfig values.
49
51
  *
50
52
  * @param endpointKey - Key identifying the endpoint (for method/header lookup)
51
53
  * @param endpointPath - The endpoint path template
@@ -7,6 +7,8 @@
7
7
  */
8
8
  import { buildEndpointUrl, getEndpointMethod, getEndpointHeaders } from '../config/endpoints.js';
9
9
  import { NoAuthProvider } from '../types/auth.js';
10
+ import { get } from 'svelte/store';
11
+ import { apiSettings } from '../stores/settingsStore.js';
10
12
  /**
11
13
  * API error with additional context
12
14
  */
@@ -54,7 +56,9 @@ export class EnhancedFlowDropApiClient {
54
56
  this.authProvider = authProvider ?? new NoAuthProvider();
55
57
  }
56
58
  /**
57
- * Make HTTP request with error handling, retry logic, and auth support
59
+ * Make HTTP request with error handling, retry logic, timeout, and auth support
60
+ *
61
+ * Uses apiSettings for timeout and retry configuration, falling back to EndpointConfig values.
58
62
  *
59
63
  * @param endpointKey - Key identifying the endpoint (for method/header lookup)
60
64
  * @param endpointPath - The endpoint path template
@@ -66,6 +70,8 @@ export class EnhancedFlowDropApiClient {
66
70
  const url = buildEndpointUrl(this.config, endpointPath, params);
67
71
  const method = options.method ?? getEndpointMethod(this.config, endpointKey);
68
72
  const configHeaders = getEndpointHeaders(this.config, endpointKey);
73
+ // Get user settings for timeout and retry
74
+ const userApiSettings = get(apiSettings);
69
75
  // Get auth headers from provider
70
76
  const authHeaders = await this.authProvider.getAuthHeaders();
71
77
  // Merge headers: config headers < auth headers < request-specific headers
@@ -74,16 +80,27 @@ export class EnhancedFlowDropApiClient {
74
80
  ...authHeaders,
75
81
  ...options.headers
76
82
  };
83
+ // Create AbortController for timeout
84
+ const controller = new AbortController();
85
+ const timeoutMs = userApiSettings.timeout ?? this.config.timeout ?? 30000;
86
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
77
87
  const fetchConfig = {
78
88
  method,
79
89
  headers,
90
+ signal: controller.signal,
80
91
  ...options
81
92
  };
82
93
  let lastError = null;
83
- const maxAttempts = this.config.retry?.enabled ? this.config.retry.maxAttempts : 1;
94
+ // Determine retry settings: user settings override config
95
+ const retryEnabled = userApiSettings.retryEnabled ?? this.config.retry?.enabled ?? false;
96
+ const maxAttempts = retryEnabled
97
+ ? (userApiSettings.retryAttempts ?? this.config.retry?.maxAttempts ?? 3)
98
+ : 1;
84
99
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
85
100
  try {
86
101
  const response = await fetch(url, fetchConfig);
102
+ // Clear timeout on successful response
103
+ clearTimeout(timeoutId);
87
104
  // Handle 401 Unauthorized
88
105
  if (response.status === 401) {
89
106
  if (this.authProvider.onUnauthorized) {
@@ -117,6 +134,17 @@ export class EnhancedFlowDropApiClient {
117
134
  return data;
118
135
  }
119
136
  catch (error) {
137
+ // Clear timeout on error
138
+ clearTimeout(timeoutId);
139
+ // Handle abort (timeout)
140
+ if (error instanceof Error && error.name === 'AbortError') {
141
+ lastError = new ApiError(`Request timeout after ${timeoutMs}ms`, 0, operation, {
142
+ timeout: true
143
+ });
144
+ // Don't retry on timeout - it's a client-side timeout
145
+ console.error(`API request timed out after ${timeoutMs}ms:`, lastError);
146
+ throw lastError;
147
+ }
120
148
  // If it's already an ApiError, preserve it
121
149
  if (error instanceof ApiError) {
122
150
  lastError = error;
@@ -131,9 +159,11 @@ export class EnhancedFlowDropApiClient {
131
159
  console.error(`API request failed after ${attempt} attempts:`, lastError);
132
160
  throw lastError;
133
161
  }
134
- // Wait before retry
135
- const delay = this.config.retry?.delay ?? 1000;
136
- const backoffDelay = this.config.retry?.backoff === 'exponential' ? delay * Math.pow(2, attempt - 1) : delay;
162
+ // Wait before retry with exponential backoff
163
+ const baseDelay = this.config.retry?.delay ?? 1000;
164
+ const backoffDelay = this.config.retry?.backoff === 'exponential'
165
+ ? baseDelay * Math.pow(2, attempt - 1)
166
+ : baseDelay;
137
167
  await new Promise((resolve) => setTimeout(resolve, backoffDelay));
138
168
  }
139
169
  }
@@ -34,6 +34,8 @@
34
34
  markAsSaved
35
35
  } from '../stores/workflowStore.js';
36
36
  import { apiToasts, dismissToast } from '../services/toastService.js';
37
+ import { initAutoSave } from '../services/autoSaveService.js';
38
+ import { uiSettings } from '../stores/settingsStore.js';
37
39
 
38
40
  /**
39
41
  * Configuration props for runtime customization
@@ -599,8 +601,23 @@
599
601
 
600
602
  window.addEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
601
603
 
604
+ // Initialize auto-save based on user settings
605
+ const cleanupAutoSave = initAutoSave({
606
+ onSave: async () => {
607
+ await saveWorkflow();
608
+ },
609
+ onError: (error) => {
610
+ // Don't show toast for auto-save errors to avoid noise
611
+ console.warn('Auto-save failed:', error);
612
+ },
613
+ onSuccess: () => {
614
+ console.debug('Auto-saved workflow');
615
+ }
616
+ });
617
+
602
618
  return () => {
603
619
  window.removeEventListener('workflow-settings-toggle', handleWorkflowSettingsToggle);
620
+ cleanupAutoSave();
604
621
  };
605
622
  });
606
623
 
@@ -611,6 +628,19 @@
611
628
  // Workflow store updated
612
629
  }
613
630
  });
631
+
632
+ /**
633
+ * Derived value for showing the right config panel
634
+ * Config panel always appears on the right side
635
+ */
636
+ const hasConfigPanelOpen = $derived(isWorkflowSettingsOpen || !!selectedNodeForConfig());
637
+ const showRightPanel = $derived(!disableSidebar && hasConfigPanelOpen);
638
+
639
+ /**
640
+ * Calculate left sidebar width based on collapsed state
641
+ * When collapsed, use 48px; otherwise use user-configured width
642
+ */
643
+ const leftSidebarWidth = $derived($uiSettings.sidebarCollapsed ? 48 : $uiSettings.sidebarWidth);
614
644
  </script>
615
645
 
616
646
  <svelte:head>
@@ -622,13 +652,14 @@
622
652
  <MainLayout
623
653
  showHeader={showNavbar && !$page.url.pathname.includes('/edit')}
624
654
  showLeftSidebar={!disableSidebar}
625
- showRightSidebar={!disableSidebar && (isWorkflowSettingsOpen || !!selectedNodeForConfig())}
655
+ showRightSidebar={showRightPanel}
656
+ showBottomPanel={false}
626
657
  showFooter={false}
627
658
  headerHeight={60}
628
- leftSidebarWidth={320}
659
+ {leftSidebarWidth}
629
660
  rightSidebarWidth={400}
630
- leftSidebarMinWidth={280}
631
- leftSidebarMaxWidth={450}
661
+ leftSidebarMinWidth={$uiSettings.sidebarCollapsed ? 48 : 280}
662
+ leftSidebarMaxWidth={$uiSettings.sidebarCollapsed ? 48 : 450}
632
663
  rightSidebarMinWidth={320}
633
664
  rightSidebarMaxWidth={550}
634
665
  enableLeftSplitPane={false}
@@ -699,8 +730,15 @@
699
730
  schema={workflowConfigSchema}
700
731
  values={workflowConfigValues}
701
732
  showUIExtensions={false}
702
- onSave={handleWorkflowSave}
703
- onCancel={() => (isWorkflowSettingsOpen = false)}
733
+ onChange={(config) => {
734
+ // Sync workflow settings changes immediately on field blur
735
+ if ($workflowStore) {
736
+ workflowActions.batchUpdate({
737
+ name: config.name as string,
738
+ description: config.description as string | undefined
739
+ });
740
+ }
741
+ }}
704
742
  />
705
743
  </ConfigPanel>
706
744
  {:else if selectedNodeForConfig()}
@@ -718,7 +756,8 @@
718
756
  <ConfigForm
719
757
  node={currentNode}
720
758
  workflowId={$workflowStore?.id}
721
- onSave={async (updatedConfig, uiExtensions?: NodeUIExtensions) => {
759
+ onChange={async (updatedConfig, uiExtensions) => {
760
+ // Sync config changes to workflow immediately on field blur
722
761
  if (selectedNodeId && currentNode) {
723
762
  // Build the updated node data
724
763
  const updatedData = {
@@ -734,22 +773,17 @@
734
773
  };
735
774
  }
736
775
 
737
- // Handle nodeType switching if nodeType is in the config
776
+ // Update the node in the workflow store
738
777
  const nodeUpdates: Record<string, unknown> = {
739
778
  data: updatedData
740
779
  };
741
780
 
742
- // NOTE: We do NOT change the node's type field anymore
743
- // All nodes use 'universalNode' and UniversalNode handles internal switching
744
781
  workflowActions.updateNode(selectedNodeId, nodeUpdates);
745
782
 
746
- // Refresh edge positions just in case. This is a safe bet.
783
+ // Refresh edge positions in case config changes affect handles
747
784
  await workflowEditorRef.refreshEdgePositions(selectedNodeId);
748
785
  }
749
-
750
- closeConfigSidebar();
751
786
  }}
752
- onCancel={closeConfigSidebar}
753
787
  />
754
788
  </ConfigPanel>
755
789
  {/if}
@@ -837,14 +871,14 @@
837
871
  <style>
838
872
  /* Status bar styles */
839
873
  .flowdrop-status {
840
- background-color: #eff6ff;
841
- border-bottom: 1px solid #bfdbfe;
874
+ background-color: var(--fd-info-muted);
875
+ border-bottom: 1px solid var(--fd-info);
842
876
  padding: 1rem;
843
877
  }
844
878
 
845
879
  .flowdrop-status--error {
846
- background-color: #fef2f2;
847
- border-bottom: 1px solid #fecaca;
880
+ background-color: var(--fd-error-muted);
881
+ border-bottom: 1px solid var(--fd-error);
848
882
  }
849
883
 
850
884
  .flowdrop-status__content {
@@ -862,18 +896,18 @@
862
896
  }
863
897
 
864
898
  .flowdrop-status__indicator--error {
865
- background-color: #ef4444;
899
+ background-color: var(--fd-error);
866
900
  }
867
901
 
868
902
  /* Button styles */
869
903
  .flowdrop-btn {
870
904
  padding: 0.375rem 0.75rem;
871
- border-radius: 0.375rem;
905
+ border-radius: var(--fd-radius-md);
872
906
  font-size: 0.75rem;
873
907
  font-weight: 500;
874
908
  cursor: pointer;
875
909
  border: 1px solid transparent;
876
- transition: all 0.2s ease-in-out;
910
+ transition: all var(--fd-transition-fast);
877
911
  }
878
912
 
879
913
  .flowdrop-btn--sm {
@@ -883,35 +917,35 @@
883
917
 
884
918
  .flowdrop-btn--outline {
885
919
  background-color: transparent;
886
- border-color: #d1d5db;
887
- color: #374151;
920
+ border-color: var(--fd-border);
921
+ color: var(--fd-foreground);
888
922
  }
889
923
 
890
924
  .flowdrop-btn--outline:hover {
891
- background-color: #f9fafb;
892
- border-color: #9ca3af;
925
+ background-color: var(--fd-muted);
926
+ border-color: var(--fd-border-strong);
893
927
  }
894
928
 
895
929
  .flowdrop-btn--primary {
896
- background-color: #3b82f6;
897
- border-color: #3b82f6;
898
- color: #ffffff;
930
+ background-color: var(--fd-primary);
931
+ border-color: var(--fd-primary);
932
+ color: var(--fd-primary-foreground);
899
933
  }
900
934
 
901
935
  .flowdrop-btn--primary:hover {
902
- background-color: #2563eb;
903
- border-color: #2563eb;
936
+ background-color: var(--fd-primary-hover);
937
+ border-color: var(--fd-primary-hover);
904
938
  }
905
939
 
906
940
  .flowdrop-btn--ghost {
907
941
  background-color: transparent;
908
942
  border-color: transparent;
909
- color: #6b7280;
943
+ color: var(--fd-muted-foreground);
910
944
  }
911
945
 
912
946
  .flowdrop-btn--ghost:hover {
913
- background-color: #f3f4f6;
914
- color: #374151;
947
+ background-color: var(--fd-muted);
948
+ color: var(--fd-foreground);
915
949
  }
916
950
 
917
951
  /* Utility classes */
@@ -943,6 +977,6 @@
943
977
  min-width: 0;
944
978
  height: 100%;
945
979
  overflow: hidden;
946
- background-color: #1f2937;
980
+ background: var(--fd-layout-background);
947
981
  }
948
982
  </style>