@d34dman/flowdrop 0.0.60 → 0.0.62
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.
- package/README.md +6 -0
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -1
- package/dist/api/client.d.ts +4 -0
- package/dist/api/client.js +6 -1
- package/dist/api/enhanced-client.js +7 -6
- package/dist/components/App.svelte +143 -219
- package/dist/components/CanvasBanner.stories.svelte +25 -0
- package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
- package/dist/components/CanvasBanner.svelte +2 -2
- package/dist/components/ConfigForm.svelte +37 -36
- package/dist/components/ConfigPanel.stories.svelte +38 -0
- package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
- package/dist/components/ConfigPanel.svelte +2 -2
- package/dist/components/ConnectionLine.svelte +2 -2
- package/dist/components/FlowDropZone.svelte +18 -2
- package/dist/components/FlowDropZone.svelte.d.ts +2 -0
- package/dist/components/LoadingSpinner.stories.svelte +30 -0
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.stories.svelte +22 -0
- package/dist/components/Logo.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.svelte +33 -13
- package/dist/components/Logo.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.stories.svelte +21 -0
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
- package/dist/components/MarkdownDisplay.svelte +4 -3
- package/dist/components/Navbar.stories.svelte +41 -0
- package/dist/components/Navbar.stories.svelte.d.ts +27 -0
- package/dist/components/Navbar.svelte +4 -4
- package/dist/components/NodeSidebar.svelte +12 -12
- package/dist/components/NodeStatusOverlay.stories.svelte +74 -0
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
- package/dist/components/PipelineStatus.svelte +11 -4
- package/dist/components/PortCoordinateTracker.svelte +1 -1
- package/dist/components/SchemaForm.stories.svelte +101 -0
- package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
- package/dist/components/SchemaForm.svelte +17 -12
- package/dist/components/SettingsModal.svelte +3 -3
- package/dist/components/SettingsPanel.svelte +23 -22
- package/dist/components/StatusIcon.stories.svelte +60 -0
- package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
- package/dist/components/StatusIcon.svelte +7 -0
- package/dist/components/StatusLabel.stories.svelte +17 -0
- package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.stories.svelte +25 -0
- package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.svelte +8 -8
- package/dist/components/UniversalNode.svelte +1 -1
- package/dist/components/WorkflowEditor.svelte +298 -294
- package/dist/components/form/FormAutocomplete.svelte +20 -19
- package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormField.svelte +3 -3
- package/dist/components/form/FormFieldLight.svelte +2 -2
- package/dist/components/form/FormFieldWrapper.stories.svelte +31 -0
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormFieldset.svelte +7 -7
- package/dist/components/form/FormNumberField.stories.svelte +33 -0
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormRangeField.stories.svelte +31 -0
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormSelect.stories.svelte +50 -0
- package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTemplateEditor.svelte +2 -1
- package/dist/components/form/FormTextField.stories.svelte +30 -0
- package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTextarea.stories.svelte +31 -0
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormToggle.stories.svelte +30 -0
- package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormUISchemaRenderer.svelte +1 -1
- package/dist/components/form/types.d.ts +15 -47
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +43 -0
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +24 -24
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +49 -0
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +19 -19
- package/dist/components/interrupt/FormPrompt.svelte +15 -15
- package/dist/components/interrupt/InterruptBubble.svelte +202 -236
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +1 -1
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +46 -0
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ReviewPrompt.svelte +842 -0
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +34 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +21 -21
- package/dist/components/nodes/GatewayNode.stories.svelte +76 -0
- package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/GatewayNode.svelte +19 -17
- package/dist/components/nodes/IdeaNode.stories.svelte +48 -0
- package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/IdeaNode.svelte +10 -26
- package/dist/components/nodes/NotesNode.stories.svelte +69 -0
- package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/NotesNode.svelte +8 -8
- package/dist/components/nodes/SimpleNode.stories.svelte +101 -0
- package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SimpleNode.svelte +16 -24
- package/dist/components/nodes/SquareNode.stories.svelte +56 -0
- package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SquareNode.svelte +13 -21
- package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
- package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/TerminalNode.svelte +6 -6
- package/dist/components/nodes/ToolNode.stories.svelte +71 -0
- package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/ToolNode.svelte +7 -15
- package/dist/components/nodes/WorkflowNode.stories.svelte +50 -0
- package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/WorkflowNode.svelte +13 -13
- package/dist/components/playground/ChatPanel.svelte +48 -48
- package/dist/components/playground/ExecutionLogs.svelte +23 -23
- package/dist/components/playground/InputCollector.svelte +24 -24
- package/dist/components/playground/MessageBubble.stories.svelte +49 -0
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
- package/dist/components/playground/MessageBubble.svelte +49 -46
- package/dist/components/playground/Playground.svelte +203 -172
- package/dist/components/playground/PlaygroundModal.svelte +5 -5
- package/dist/components/playground/SessionManager.svelte +26 -26
- package/dist/config/constants.d.ts +22 -0
- package/dist/config/constants.js +22 -0
- package/dist/config/endpoints.d.ts +19 -0
- package/dist/config/runtimeConfig.js +2 -1
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.js +9 -1
- package/dist/editor/index.d.ts +13 -9
- package/dist/editor/index.js +15 -11
- package/dist/form/code.d.ts +2 -1
- package/dist/form/code.js +1 -3
- package/dist/form/markdown.d.ts +2 -1
- package/dist/form/markdown.js +1 -3
- package/dist/helpers/workflowEditorHelper.js +13 -9
- package/dist/mocks/app-forms.js +1 -0
- package/dist/mocks/app-navigation.js +3 -1
- package/dist/mocks/app-stores.d.ts +4 -4
- package/dist/playground/index.d.ts +5 -4
- package/dist/playground/index.js +15 -11
- package/dist/playground/mount.d.ts +20 -1
- package/dist/playground/mount.js +24 -6
- package/dist/services/agentSpecExecutionService.js +2 -1
- package/dist/services/api.js +10 -18
- package/dist/services/apiVariableService.js +2 -1
- package/dist/services/autoSaveService.d.ts +3 -3
- package/dist/services/autoSaveService.js +21 -17
- package/dist/services/categoriesApi.js +13 -5
- package/dist/services/draftStorage.js +5 -4
- package/dist/services/dynamicSchemaService.js +4 -4
- package/dist/services/globalSave.d.ts +60 -11
- package/dist/services/globalSave.js +160 -83
- package/dist/services/historyService.d.ts +2 -1
- package/dist/services/historyService.js +7 -3
- package/dist/services/interruptService.js +9 -8
- package/dist/services/nodeExecutionService.js +14 -6
- package/dist/services/playgroundService.d.ts +3 -2
- package/dist/services/playgroundService.js +8 -7
- package/dist/services/portConfigApi.js +11 -7
- package/dist/services/toastService.d.ts +1 -1
- package/dist/services/toastService.js +6 -5
- package/dist/services/variableService.js +3 -2
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js +1 -1
- package/dist/stores/{categoriesStore.d.ts → categoriesStore.svelte.d.ts} +3 -3
- package/dist/stores/{categoriesStore.js → categoriesStore.svelte.js} +15 -18
- package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
- package/dist/stores/editorStateMachine.svelte.js +132 -0
- package/dist/stores/{historyStore.d.ts → historyStore.svelte.d.ts} +18 -15
- package/dist/stores/{historyStore.js → historyStore.svelte.js} +40 -21
- package/dist/stores/{interruptStore.d.ts → interruptStore.svelte.d.ts} +16 -15
- package/dist/stores/{interruptStore.js → interruptStore.svelte.js} +85 -94
- package/dist/stores/{playgroundStore.d.ts → playgroundStore.svelte.d.ts} +52 -34
- package/dist/stores/{playgroundStore.js → playgroundStore.svelte.js} +193 -100
- package/dist/stores/{portCoordinateStore.d.ts → portCoordinateStore.svelte.d.ts} +10 -4
- package/dist/stores/{portCoordinateStore.js → portCoordinateStore.svelte.js} +38 -35
- package/dist/stores/{settingsStore.d.ts → settingsStore.svelte.d.ts} +45 -28
- package/dist/stores/{settingsStore.js → settingsStore.svelte.js} +169 -128
- package/dist/stores/{workflowStore.d.ts → workflowStore.svelte.d.ts} +101 -65
- package/dist/stores/{workflowStore.js → workflowStore.svelte.js} +285 -239
- package/dist/stories/CanvasDecorator.svelte +50 -0
- package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
- package/dist/stories/NodeDecorator.svelte +74 -0
- package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
- package/dist/stories/utils.d.ts +93 -0
- package/dist/stories/utils.js +122 -0
- package/dist/styles/base.css +114 -61
- package/dist/styles/toast.css +2 -2
- package/dist/styles/tokens.css +250 -185
- package/dist/svelte-app.d.ts +0 -6
- package/dist/svelte-app.js +13 -31
- package/dist/types/index.d.ts +2 -0
- package/dist/types/interrupt.d.ts +89 -5
- package/dist/types/interrupt.js +13 -1
- package/dist/types/playground.d.ts +42 -1
- package/dist/types/playground.js +38 -0
- package/dist/types/settings.js +1 -1
- package/dist/utils/colors.js +4 -4
- package/dist/utils/connections.js +33 -8
- package/dist/utils/icons.js +1 -1
- package/dist/utils/logger.d.ts +47 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/nodeWrapper.js +1 -1
- package/dist/utils/sanitize.d.ts +19 -0
- package/dist/utils/sanitize.js +31 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.js +39 -0
- package/package.json +243 -232
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings Store for FlowDrop
|
|
2
|
+
* Settings Store for FlowDrop (Svelte 5 Runes)
|
|
3
3
|
*
|
|
4
4
|
* Provides unified state management for all user-configurable settings with:
|
|
5
5
|
* - Hybrid persistence (localStorage primary, optional API sync)
|
|
6
|
-
* - Category-specific
|
|
6
|
+
* - Category-specific getter functions for performance
|
|
7
7
|
* - Deep merge support for partial updates
|
|
8
8
|
* - Integrated theme system with system preference detection
|
|
9
9
|
*
|
|
10
10
|
* @module stores/settingsStore
|
|
11
11
|
*/
|
|
12
|
-
import { writable, derived, get } from 'svelte/store';
|
|
13
12
|
import { DEFAULT_SETTINGS, SETTINGS_STORAGE_KEY } from '../types/settings.js';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
14
|
// =========================================================================
|
|
15
15
|
// Internal State
|
|
16
16
|
// =========================================================================
|
|
@@ -44,7 +44,7 @@ function loadFromStorage() {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
catch (error) {
|
|
47
|
-
|
|
47
|
+
logger.warn('Failed to load settings from localStorage:', error);
|
|
48
48
|
}
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
@@ -61,7 +61,7 @@ function saveToStorage(settings) {
|
|
|
61
61
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings));
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
|
-
|
|
64
|
+
logger.warn('Failed to save settings to localStorage:', error);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
// =========================================================================
|
|
@@ -105,16 +105,16 @@ function deepMergeSettings(target, source) {
|
|
|
105
105
|
return result;
|
|
106
106
|
}
|
|
107
107
|
// =========================================================================
|
|
108
|
-
// Main Settings Store
|
|
108
|
+
// Main Settings Store (Rune-based)
|
|
109
109
|
// =========================================================================
|
|
110
110
|
/**
|
|
111
111
|
* Initial state loaded from localStorage or defaults
|
|
112
112
|
*/
|
|
113
113
|
const initialSettings = loadFromStorage() ?? DEFAULT_SETTINGS;
|
|
114
114
|
/**
|
|
115
|
-
* Main settings store state
|
|
115
|
+
* Main settings store state using $state rune
|
|
116
116
|
*/
|
|
117
|
-
|
|
117
|
+
let storeState = $state({
|
|
118
118
|
settings: initialSettings,
|
|
119
119
|
initialized: true,
|
|
120
120
|
syncStatus: 'idle',
|
|
@@ -122,48 +122,85 @@ const storeState = writable({
|
|
|
122
122
|
syncError: null
|
|
123
123
|
});
|
|
124
124
|
/**
|
|
125
|
-
*
|
|
126
|
-
|
|
127
|
-
export const settingsStore = derived(storeState, ($state) => $state.settings);
|
|
128
|
-
/**
|
|
129
|
-
* Sync status store for UI indicators
|
|
125
|
+
* System theme preference using $state rune
|
|
126
|
+
* Updates when system preference changes
|
|
130
127
|
*/
|
|
131
|
-
|
|
132
|
-
status: $state.syncStatus,
|
|
133
|
-
lastSyncedAt: $state.lastSyncedAt,
|
|
134
|
-
error: $state.syncError
|
|
135
|
-
}));
|
|
128
|
+
let systemThemeState = $state(typeof window !== 'undefined' ? getSystemTheme() : 'light');
|
|
136
129
|
// =========================================================================
|
|
137
|
-
//
|
|
130
|
+
// Getter Functions (replacing derived stores)
|
|
138
131
|
// =========================================================================
|
|
139
132
|
/**
|
|
140
|
-
*
|
|
133
|
+
* Get current settings (replaces settingsStore derived store)
|
|
134
|
+
*/
|
|
135
|
+
export function getSettings() {
|
|
136
|
+
return storeState.settings;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get sync status (replaces syncStatusStore derived store)
|
|
140
|
+
*/
|
|
141
|
+
export function getSyncStatus() {
|
|
142
|
+
return {
|
|
143
|
+
status: storeState.syncStatus,
|
|
144
|
+
lastSyncedAt: storeState.lastSyncedAt,
|
|
145
|
+
error: storeState.syncError
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get theme settings (replaces themeSettings derived store)
|
|
150
|
+
*/
|
|
151
|
+
export function getThemeSettings() {
|
|
152
|
+
return storeState.settings.theme;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get editor settings (replaces editorSettings derived store)
|
|
156
|
+
*/
|
|
157
|
+
export function getEditorSettings() {
|
|
158
|
+
return storeState.settings.editor;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get UI settings (replaces uiSettings derived store)
|
|
162
|
+
*/
|
|
163
|
+
export function getUiSettings() {
|
|
164
|
+
return storeState.settings.ui;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get behavior settings (replaces behaviorSettings derived store)
|
|
141
168
|
*/
|
|
142
|
-
export
|
|
169
|
+
export function getBehaviorSettings() {
|
|
170
|
+
return storeState.settings.behavior;
|
|
171
|
+
}
|
|
143
172
|
/**
|
|
144
|
-
*
|
|
173
|
+
* Get API settings (replaces apiSettings derived store)
|
|
145
174
|
*/
|
|
146
|
-
export
|
|
175
|
+
export function getApiSettings() {
|
|
176
|
+
return storeState.settings.api;
|
|
177
|
+
}
|
|
147
178
|
/**
|
|
148
|
-
*
|
|
179
|
+
* Get theme preference (replaces theme derived store)
|
|
149
180
|
*/
|
|
150
|
-
export
|
|
181
|
+
export function getTheme() {
|
|
182
|
+
return storeState.settings.theme.preference;
|
|
183
|
+
}
|
|
151
184
|
/**
|
|
152
|
-
*
|
|
185
|
+
* Get resolved theme - the actual theme applied ('light' or 'dark')
|
|
186
|
+
* When preference is 'auto', resolves based on system preference
|
|
187
|
+
* (replaces resolvedTheme derived store)
|
|
153
188
|
*/
|
|
154
|
-
export
|
|
189
|
+
export function getResolvedTheme() {
|
|
190
|
+
if (storeState.settings.theme.preference === 'auto') {
|
|
191
|
+
return systemThemeState;
|
|
192
|
+
}
|
|
193
|
+
return storeState.settings.theme.preference;
|
|
194
|
+
}
|
|
155
195
|
/**
|
|
156
|
-
*
|
|
196
|
+
* Get system theme state (for internal use)
|
|
157
197
|
*/
|
|
158
|
-
export
|
|
198
|
+
export function getSystemThemeState() {
|
|
199
|
+
return systemThemeState;
|
|
200
|
+
}
|
|
159
201
|
// =========================================================================
|
|
160
202
|
// Theme System
|
|
161
203
|
// =========================================================================
|
|
162
|
-
/**
|
|
163
|
-
* System theme preference store
|
|
164
|
-
* Updates when system preference changes
|
|
165
|
-
*/
|
|
166
|
-
const systemTheme = writable(typeof window !== 'undefined' ? getSystemTheme() : 'light');
|
|
167
204
|
/**
|
|
168
205
|
* Get the system's color scheme preference
|
|
169
206
|
*/
|
|
@@ -173,35 +210,25 @@ function getSystemTheme() {
|
|
|
173
210
|
}
|
|
174
211
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
175
212
|
}
|
|
176
|
-
|
|
177
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Initialize the system theme change listener.
|
|
215
|
+
* Sets up a media query listener for the system color scheme preference.
|
|
216
|
+
*
|
|
217
|
+
* @returns Cleanup function that removes the listener
|
|
218
|
+
*/
|
|
219
|
+
export function initThemeListener() {
|
|
220
|
+
if (typeof window === 'undefined') {
|
|
221
|
+
return () => { };
|
|
222
|
+
}
|
|
178
223
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
179
224
|
const handleSystemThemeChange = (event) => {
|
|
180
|
-
|
|
225
|
+
systemThemeState = event.matches ? 'dark' : 'light';
|
|
226
|
+
};
|
|
227
|
+
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
|
228
|
+
return () => {
|
|
229
|
+
mediaQuery.removeEventListener('change', handleSystemThemeChange);
|
|
181
230
|
};
|
|
182
|
-
if (mediaQuery.addEventListener) {
|
|
183
|
-
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
// Fallback for older browsers
|
|
187
|
-
mediaQuery.addListener(handleSystemThemeChange);
|
|
188
|
-
}
|
|
189
231
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Theme preference store
|
|
192
|
-
* Derived from themeSettings for convenient access
|
|
193
|
-
*/
|
|
194
|
-
export const theme = derived(themeSettings, ($theme) => $theme.preference);
|
|
195
|
-
/**
|
|
196
|
-
* Resolved theme - the actual theme applied ('light' or 'dark')
|
|
197
|
-
* When preference is 'auto', resolves based on system preference
|
|
198
|
-
*/
|
|
199
|
-
export const resolvedTheme = derived([themeSettings, systemTheme], ([$themeSettings, $systemTheme]) => {
|
|
200
|
-
if ($themeSettings.preference === 'auto') {
|
|
201
|
-
return $systemTheme;
|
|
202
|
-
}
|
|
203
|
-
return $themeSettings.preference;
|
|
204
|
-
});
|
|
205
232
|
// =========================================================================
|
|
206
233
|
// Settings Update Functions
|
|
207
234
|
// =========================================================================
|
|
@@ -220,7 +247,7 @@ function notifyChange(category, key, previousValue, newValue) {
|
|
|
220
247
|
listener(event);
|
|
221
248
|
}
|
|
222
249
|
catch (error) {
|
|
223
|
-
|
|
250
|
+
logger.error('Settings change listener error:', error);
|
|
224
251
|
}
|
|
225
252
|
});
|
|
226
253
|
}
|
|
@@ -236,29 +263,27 @@ function getCategoryAsRecord(settings, category) {
|
|
|
236
263
|
* @param partial - Partial settings to merge
|
|
237
264
|
*/
|
|
238
265
|
export function updateSettings(partial) {
|
|
239
|
-
storeState.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
notifyChange(category, key, prevCat[key], newCat[key]);
|
|
253
|
-
}
|
|
266
|
+
const previousSettings = storeState.settings;
|
|
267
|
+
const newSettings = deepMergeSettings(storeState.settings, partial);
|
|
268
|
+
// Persist to localStorage immediately
|
|
269
|
+
saveToStorage(newSettings);
|
|
270
|
+
// Notify listeners for each changed category
|
|
271
|
+
for (const category of Object.keys(partial)) {
|
|
272
|
+
const partialCategory = partial[category];
|
|
273
|
+
if (partialCategory && typeof partialCategory === 'object') {
|
|
274
|
+
for (const key of Object.keys(partialCategory)) {
|
|
275
|
+
const prevCat = getCategoryAsRecord(previousSettings, category);
|
|
276
|
+
const newCat = getCategoryAsRecord(newSettings, category);
|
|
277
|
+
if (prevCat[key] !== newCat[key]) {
|
|
278
|
+
notifyChange(category, key, prevCat[key], newCat[key]);
|
|
254
279
|
}
|
|
255
280
|
}
|
|
256
281
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
282
|
+
}
|
|
283
|
+
storeState = {
|
|
284
|
+
...storeState,
|
|
285
|
+
settings: newSettings
|
|
286
|
+
};
|
|
262
287
|
}
|
|
263
288
|
/**
|
|
264
289
|
* Reset settings to defaults
|
|
@@ -274,21 +299,13 @@ export function resetSettings(categories) {
|
|
|
274
299
|
updateSettings(partial);
|
|
275
300
|
}
|
|
276
301
|
else {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
};
|
|
283
|
-
});
|
|
302
|
+
saveToStorage(DEFAULT_SETTINGS);
|
|
303
|
+
storeState = {
|
|
304
|
+
...storeState,
|
|
305
|
+
settings: DEFAULT_SETTINGS
|
|
306
|
+
};
|
|
284
307
|
}
|
|
285
308
|
}
|
|
286
|
-
/**
|
|
287
|
-
* Get current settings synchronously
|
|
288
|
-
*/
|
|
289
|
-
export function getSettings() {
|
|
290
|
-
return get(settingsStore);
|
|
291
|
-
}
|
|
292
309
|
// =========================================================================
|
|
293
310
|
// Theme Actions
|
|
294
311
|
// =========================================================================
|
|
@@ -305,8 +322,8 @@ export function setTheme(newTheme) {
|
|
|
305
322
|
* If currently 'auto', switches to the opposite of system preference
|
|
306
323
|
*/
|
|
307
324
|
export function toggleTheme() {
|
|
308
|
-
const currentTheme =
|
|
309
|
-
const currentResolved =
|
|
325
|
+
const currentTheme = getTheme();
|
|
326
|
+
const currentResolved = getResolvedTheme();
|
|
310
327
|
if (currentTheme === 'auto') {
|
|
311
328
|
setTheme(currentResolved === 'dark' ? 'light' : 'dark');
|
|
312
329
|
}
|
|
@@ -318,7 +335,7 @@ export function toggleTheme() {
|
|
|
318
335
|
* Cycle through theme options: light -> dark -> auto -> light
|
|
319
336
|
*/
|
|
320
337
|
export function cycleTheme() {
|
|
321
|
-
const currentTheme =
|
|
338
|
+
const currentTheme = getTheme();
|
|
322
339
|
switch (currentTheme) {
|
|
323
340
|
case 'light':
|
|
324
341
|
setTheme('dark');
|
|
@@ -342,6 +359,22 @@ function applyTheme(resolved) {
|
|
|
342
359
|
}
|
|
343
360
|
document.documentElement.setAttribute('data-theme', resolved);
|
|
344
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Stored cleanup function for the theme effect.
|
|
364
|
+
* Retained so it can be called by cleanupThemeSubscription().
|
|
365
|
+
*/
|
|
366
|
+
let themeEffectCleanup = null;
|
|
367
|
+
/**
|
|
368
|
+
* Clean up the theme subscription created by initializeTheme().
|
|
369
|
+
* Call this when tearing down the settings system (e.g., in tests or
|
|
370
|
+
* component cleanup) to prevent memory leaks.
|
|
371
|
+
*/
|
|
372
|
+
export function cleanupThemeSubscription() {
|
|
373
|
+
if (themeEffectCleanup) {
|
|
374
|
+
themeEffectCleanup();
|
|
375
|
+
themeEffectCleanup = null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
345
378
|
/**
|
|
346
379
|
* Initialize the theme system
|
|
347
380
|
* Should be called once on app startup
|
|
@@ -349,13 +382,21 @@ function applyTheme(resolved) {
|
|
|
349
382
|
* This function:
|
|
350
383
|
* 1. Applies the current resolved theme to the document
|
|
351
384
|
* 2. Sets up reactivity to apply theme changes
|
|
385
|
+
*
|
|
386
|
+
* Note: In Svelte 5, we use $effect for reactivity. Since $effect can only
|
|
387
|
+
* be used in component context or $effect.root, we use $effect.root here
|
|
388
|
+
* to create a standalone reactive scope.
|
|
352
389
|
*/
|
|
353
390
|
export function initializeTheme() {
|
|
354
|
-
const resolved =
|
|
391
|
+
const resolved = getResolvedTheme();
|
|
355
392
|
applyTheme(resolved);
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
393
|
+
// Create a standalone reactive root to watch for theme changes.
|
|
394
|
+
// $effect.root returns a cleanup function.
|
|
395
|
+
themeEffectCleanup = $effect.root(() => {
|
|
396
|
+
$effect(() => {
|
|
397
|
+
const currentResolved = getResolvedTheme();
|
|
398
|
+
applyTheme(currentResolved);
|
|
399
|
+
});
|
|
359
400
|
});
|
|
360
401
|
}
|
|
361
402
|
/**
|
|
@@ -388,31 +429,31 @@ export function setSettingsService(service) {
|
|
|
388
429
|
*/
|
|
389
430
|
export async function syncSettingsToApi() {
|
|
390
431
|
if (!settingsService) {
|
|
391
|
-
|
|
432
|
+
logger.warn('Settings service not configured for API sync');
|
|
392
433
|
return;
|
|
393
434
|
}
|
|
394
|
-
storeState
|
|
395
|
-
...
|
|
435
|
+
storeState = {
|
|
436
|
+
...storeState,
|
|
396
437
|
syncStatus: 'syncing',
|
|
397
438
|
syncError: null
|
|
398
|
-
}
|
|
439
|
+
};
|
|
399
440
|
try {
|
|
400
|
-
const currentSettings =
|
|
441
|
+
const currentSettings = getSettings();
|
|
401
442
|
await settingsService.savePreferences(currentSettings);
|
|
402
|
-
storeState
|
|
403
|
-
...
|
|
443
|
+
storeState = {
|
|
444
|
+
...storeState,
|
|
404
445
|
syncStatus: 'synced',
|
|
405
446
|
lastSyncedAt: Date.now(),
|
|
406
447
|
syncError: null
|
|
407
|
-
}
|
|
448
|
+
};
|
|
408
449
|
}
|
|
409
450
|
catch (error) {
|
|
410
451
|
const errorMessage = error instanceof Error ? error.message : 'Failed to sync settings';
|
|
411
|
-
storeState
|
|
412
|
-
...
|
|
452
|
+
storeState = {
|
|
453
|
+
...storeState,
|
|
413
454
|
syncStatus: 'error',
|
|
414
455
|
syncError: errorMessage
|
|
415
|
-
}
|
|
456
|
+
};
|
|
416
457
|
throw error;
|
|
417
458
|
}
|
|
418
459
|
}
|
|
@@ -423,34 +464,34 @@ export async function syncSettingsToApi() {
|
|
|
423
464
|
*/
|
|
424
465
|
export async function loadSettingsFromApi() {
|
|
425
466
|
if (!settingsService) {
|
|
426
|
-
|
|
467
|
+
logger.warn('Settings service not configured for API sync');
|
|
427
468
|
return;
|
|
428
469
|
}
|
|
429
|
-
storeState
|
|
430
|
-
...
|
|
470
|
+
storeState = {
|
|
471
|
+
...storeState,
|
|
431
472
|
syncStatus: 'syncing',
|
|
432
473
|
syncError: null
|
|
433
|
-
}
|
|
474
|
+
};
|
|
434
475
|
try {
|
|
435
|
-
const
|
|
436
|
-
const mergedSettings = deepMergeSettings(DEFAULT_SETTINGS,
|
|
437
|
-
storeState
|
|
438
|
-
...
|
|
476
|
+
const apiSettingsData = await settingsService.getPreferences();
|
|
477
|
+
const mergedSettings = deepMergeSettings(DEFAULT_SETTINGS, apiSettingsData);
|
|
478
|
+
storeState = {
|
|
479
|
+
...storeState,
|
|
439
480
|
settings: mergedSettings,
|
|
440
481
|
syncStatus: 'synced',
|
|
441
482
|
lastSyncedAt: Date.now(),
|
|
442
483
|
syncError: null
|
|
443
|
-
}
|
|
484
|
+
};
|
|
444
485
|
// Also persist to localStorage
|
|
445
486
|
saveToStorage(mergedSettings);
|
|
446
487
|
}
|
|
447
488
|
catch (error) {
|
|
448
489
|
const errorMessage = error instanceof Error ? error.message : 'Failed to load settings from API';
|
|
449
|
-
storeState
|
|
450
|
-
...
|
|
490
|
+
storeState = {
|
|
491
|
+
...storeState,
|
|
451
492
|
syncStatus: 'error',
|
|
452
493
|
syncError: errorMessage
|
|
453
|
-
}
|
|
494
|
+
};
|
|
454
495
|
throw error;
|
|
455
496
|
}
|
|
456
497
|
}
|
|
@@ -480,12 +521,12 @@ export function onSettingsChange(callback) {
|
|
|
480
521
|
export async function initializeSettings(options) {
|
|
481
522
|
// Apply custom defaults if provided
|
|
482
523
|
if (options?.defaults) {
|
|
483
|
-
const currentSettings =
|
|
524
|
+
const currentSettings = getSettings();
|
|
484
525
|
const withDefaults = deepMergeSettings(currentSettings, options.defaults);
|
|
485
|
-
storeState
|
|
486
|
-
...
|
|
526
|
+
storeState = {
|
|
527
|
+
...storeState,
|
|
487
528
|
settings: withDefaults
|
|
488
|
-
}
|
|
529
|
+
};
|
|
489
530
|
saveToStorage(withDefaults);
|
|
490
531
|
}
|
|
491
532
|
// Initialize theme system
|
|
@@ -497,7 +538,7 @@ export async function initializeSettings(options) {
|
|
|
497
538
|
}
|
|
498
539
|
catch {
|
|
499
540
|
// Silently fail - local settings are still available
|
|
500
|
-
|
|
541
|
+
logger.warn('Failed to sync settings from API on initialization');
|
|
501
542
|
}
|
|
502
543
|
}
|
|
503
544
|
}
|
|
@@ -1,22 +1,113 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workflow Store for FlowDrop
|
|
2
|
+
* Workflow Store for FlowDrop (Svelte 5 Runes)
|
|
3
3
|
*
|
|
4
4
|
* Provides global state management for workflows with dirty state tracking
|
|
5
5
|
* and undo/redo history integration.
|
|
6
6
|
*
|
|
7
|
+
* **Important: Single-instance only.** This store uses module-level singletons.
|
|
8
|
+
* Only one FlowDrop editor instance per page is supported. Mounting multiple
|
|
9
|
+
* FlowDrop editors on the same page will cause them to share workflow state.
|
|
10
|
+
*
|
|
7
11
|
* @module stores/workflowStore
|
|
8
12
|
*/
|
|
9
13
|
import type { Workflow, WorkflowNode, WorkflowEdge } from '../types';
|
|
10
14
|
import type { WorkflowChangeType } from '../types/events.js';
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
type WorkflowMetadata = NonNullable<Workflow['metadata']>;
|
|
16
|
+
/**
|
|
17
|
+
* Get the current workflow store value reactively
|
|
18
|
+
*
|
|
19
|
+
* @returns The current workflow or null
|
|
20
|
+
*/
|
|
21
|
+
export declare function getWorkflowStore(): Workflow | null;
|
|
22
|
+
/**
|
|
23
|
+
* Get the current dirty state reactively
|
|
24
|
+
*
|
|
25
|
+
* @returns true if there are unsaved changes
|
|
26
|
+
*/
|
|
27
|
+
export declare function getIsDirty(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Get the workflow ID reactively
|
|
30
|
+
*
|
|
31
|
+
* @returns The workflow ID or null
|
|
32
|
+
*/
|
|
33
|
+
export declare function getWorkflowId(): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Get the workflow name reactively
|
|
36
|
+
*
|
|
37
|
+
* @returns The workflow name or 'Untitled Workflow'
|
|
38
|
+
*/
|
|
39
|
+
export declare function getWorkflowName(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Get the workflow nodes reactively
|
|
42
|
+
*
|
|
43
|
+
* @returns Array of workflow nodes
|
|
44
|
+
*/
|
|
45
|
+
export declare function getWorkflowNodes(): WorkflowNode[];
|
|
46
|
+
/**
|
|
47
|
+
* Get the workflow edges reactively
|
|
48
|
+
*
|
|
49
|
+
* @returns Array of workflow edges
|
|
50
|
+
*/
|
|
51
|
+
export declare function getWorkflowEdges(): WorkflowEdge[];
|
|
13
52
|
/**
|
|
14
|
-
*
|
|
53
|
+
* Get the workflow metadata reactively
|
|
15
54
|
*
|
|
16
|
-
*
|
|
17
|
-
* It can be reset to false by calling markAsSaved().
|
|
55
|
+
* @returns The workflow metadata with defaults
|
|
18
56
|
*/
|
|
19
|
-
export declare
|
|
57
|
+
export declare function getWorkflowMetadata(): WorkflowMetadata;
|
|
58
|
+
/**
|
|
59
|
+
* Get the current workflow format reactively
|
|
60
|
+
*
|
|
61
|
+
* @returns The workflow format string
|
|
62
|
+
*/
|
|
63
|
+
export declare function getWorkflowFormat(): string;
|
|
64
|
+
/**
|
|
65
|
+
* Get workflow change summary reactively (useful for triggering saves)
|
|
66
|
+
*
|
|
67
|
+
* @returns Object with nodes, edges, and name
|
|
68
|
+
*/
|
|
69
|
+
export declare function getWorkflowChanged(): {
|
|
70
|
+
nodes: WorkflowNode[];
|
|
71
|
+
edges: WorkflowEdge[];
|
|
72
|
+
name: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Get workflow validation state reactively
|
|
76
|
+
*
|
|
77
|
+
* @returns Validation info object
|
|
78
|
+
*/
|
|
79
|
+
export declare function getWorkflowValidation(): {
|
|
80
|
+
hasNodes: boolean;
|
|
81
|
+
hasEdges: boolean;
|
|
82
|
+
nodeCount: number;
|
|
83
|
+
edgeCount: number;
|
|
84
|
+
isValid: boolean;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Get workflow metadata change summary reactively
|
|
88
|
+
*
|
|
89
|
+
* @returns Metadata change info
|
|
90
|
+
*/
|
|
91
|
+
export declare function getWorkflowMetadataChanged(): {
|
|
92
|
+
createdAt: string;
|
|
93
|
+
updatedAt: string;
|
|
94
|
+
version: string;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Get connected handles reactively
|
|
98
|
+
*
|
|
99
|
+
* Provides a Set of all handle IDs that are currently connected to edges.
|
|
100
|
+
* Used by node components to implement hideUnconnectedHandles functionality.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* import { getConnectedHandles } from './workflowStore.svelte.js';
|
|
105
|
+
*
|
|
106
|
+
* // Check if a specific handle is connected
|
|
107
|
+
* const isConnected = getConnectedHandles().has('node-1-input-data');
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function getConnectedHandles(): Set<string>;
|
|
20
111
|
/**
|
|
21
112
|
* Set the dirty state change callback
|
|
22
113
|
*
|
|
@@ -36,7 +127,7 @@ export declare function setOnWorkflowChange(callback: ((workflow: Workflow, chan
|
|
|
36
127
|
*/
|
|
37
128
|
export declare function markAsSaved(): void;
|
|
38
129
|
/**
|
|
39
|
-
* Check if there are unsaved changes
|
|
130
|
+
* Check if there are unsaved changes (non-reactive version for plain TS)
|
|
40
131
|
*
|
|
41
132
|
* @returns true if there are unsaved changes
|
|
42
133
|
*/
|
|
@@ -64,32 +155,11 @@ export declare function isHistoryEnabled(): boolean;
|
|
|
64
155
|
*/
|
|
65
156
|
export declare function setRestoringFromHistory(restoring: boolean): void;
|
|
66
157
|
/**
|
|
67
|
-
* Get the current workflow
|
|
158
|
+
* Get the current workflow (non-reactive version for plain TS)
|
|
68
159
|
*
|
|
69
160
|
* @returns The current workflow or null
|
|
70
161
|
*/
|
|
71
162
|
export declare function getWorkflow(): Workflow | null;
|
|
72
|
-
/** Derived store for workflow ID */
|
|
73
|
-
export declare const workflowId: import("svelte/store").Readable<string>;
|
|
74
|
-
/** Derived store for workflow name */
|
|
75
|
-
export declare const workflowName: import("svelte/store").Readable<string>;
|
|
76
|
-
/** Derived store for workflow nodes */
|
|
77
|
-
export declare const workflowNodes: import("svelte/store").Readable<WorkflowNode[]>;
|
|
78
|
-
/** Derived store for workflow edges */
|
|
79
|
-
export declare const workflowEdges: import("svelte/store").Readable<WorkflowEdge[]>;
|
|
80
|
-
/** Derived store for workflow metadata */
|
|
81
|
-
export declare const workflowMetadata: import("svelte/store").Readable<{
|
|
82
|
-
version: string;
|
|
83
|
-
createdAt: string;
|
|
84
|
-
updatedAt: string;
|
|
85
|
-
author?: string;
|
|
86
|
-
tags?: string[];
|
|
87
|
-
versionId?: string;
|
|
88
|
-
updateNumber?: number;
|
|
89
|
-
format?: import("../types").WorkflowFormat;
|
|
90
|
-
}>;
|
|
91
|
-
/** Derived store for the current workflow format */
|
|
92
|
-
export declare const workflowFormat: import("svelte/store").Readable<import("../types").WorkflowFormat>;
|
|
93
163
|
/**
|
|
94
164
|
* Actions for updating the workflow
|
|
95
165
|
*
|
|
@@ -187,38 +257,4 @@ export declare const workflowActions: {
|
|
|
187
257
|
*/
|
|
188
258
|
pushHistory: (description?: string, workflow?: Workflow) => void;
|
|
189
259
|
};
|
|
190
|
-
|
|
191
|
-
export declare const workflowChanged: import("svelte/store").Readable<{
|
|
192
|
-
nodes: WorkflowNode[];
|
|
193
|
-
edges: WorkflowEdge[];
|
|
194
|
-
name: string;
|
|
195
|
-
}>;
|
|
196
|
-
/** Derived store for workflow validation */
|
|
197
|
-
export declare const workflowValidation: import("svelte/store").Readable<{
|
|
198
|
-
hasNodes: boolean;
|
|
199
|
-
hasEdges: boolean;
|
|
200
|
-
nodeCount: number;
|
|
201
|
-
edgeCount: number;
|
|
202
|
-
isValid: boolean;
|
|
203
|
-
}>;
|
|
204
|
-
/** Derived store for workflow metadata changes */
|
|
205
|
-
export declare const workflowMetadataChanged: import("svelte/store").Readable<{
|
|
206
|
-
createdAt: string;
|
|
207
|
-
updatedAt: string;
|
|
208
|
-
version: string;
|
|
209
|
-
}>;
|
|
210
|
-
/**
|
|
211
|
-
* Derived store for connected handles
|
|
212
|
-
*
|
|
213
|
-
* Provides a Set of all handle IDs that are currently connected to edges.
|
|
214
|
-
* Used by node components to implement hideUnconnectedHandles functionality.
|
|
215
|
-
*
|
|
216
|
-
* @example
|
|
217
|
-
* ```typescript
|
|
218
|
-
* import { connectedHandles } from './workflowStore.js';
|
|
219
|
-
*
|
|
220
|
-
* // Check if a specific handle is connected
|
|
221
|
-
* const isConnected = $connectedHandles.has('node-1-input-data');
|
|
222
|
-
* ```
|
|
223
|
-
*/
|
|
224
|
-
export declare const connectedHandles: import("svelte/store").Readable<Set<string>>;
|
|
260
|
+
export {};
|