@d34dman/flowdrop 0.0.1 → 0.0.2
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 +307 -215
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +30 -30
- package/dist/api/client.d.ts +24 -1
- package/dist/api/client.js +55 -38
- package/dist/api/enhanced-client.d.ts +46 -0
- package/dist/api/enhanced-client.js +211 -0
- package/dist/clients/ApiClient.d.ts +19 -23
- package/dist/clients/ApiClient.js +36 -34
- package/dist/components/App.svelte +1299 -230
- package/dist/components/App.svelte.d.ts +21 -1
- package/dist/components/CanvasBanner.svelte +50 -44
- package/dist/components/CanvasBanner.svelte.d.ts +5 -19
- package/dist/components/ConfigForm.svelte +555 -0
- package/dist/components/ConfigForm.svelte.d.ts +32 -0
- package/dist/components/ConfigModal.svelte +261 -0
- package/dist/components/ConfigModal.svelte.d.ts +31 -0
- package/dist/components/ConfigSidebar.svelte +934 -0
- package/dist/components/ConfigSidebar.svelte.d.ts +51 -0
- package/dist/components/ConnectionLine.svelte +32 -0
- package/dist/components/ConnectionLine.svelte.d.ts +3 -0
- package/dist/components/GatewayNode.svelte +471 -0
- package/dist/components/GatewayNode.svelte.d.ts +15 -0
- package/dist/components/LoadingSpinner.svelte +23 -23
- package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
- package/dist/components/Logo.svelte +82 -0
- package/dist/components/Logo.svelte.d.ts +26 -0
- package/dist/components/LogsSidebar.svelte +565 -0
- package/dist/components/LogsSidebar.svelte.d.ts +34 -0
- package/dist/components/MarkdownDisplay.svelte +28 -0
- package/dist/components/MarkdownDisplay.svelte.d.ts +7 -0
- package/dist/components/Navbar.svelte +663 -0
- package/dist/components/Navbar.svelte.d.ts +21 -0
- package/dist/components/NodeSidebar.svelte +629 -488
- package/dist/components/NodeSidebar.svelte.d.ts +1 -2
- package/dist/components/NodeStatusOverlay.svelte +327 -0
- package/dist/components/NodeStatusOverlay.svelte.d.ts +11 -0
- package/dist/components/NotesNode.svelte +566 -0
- package/dist/components/NotesNode.svelte.d.ts +43 -0
- package/dist/components/PipelineStatus.svelte +331 -0
- package/dist/components/PipelineStatus.svelte.d.ts +18 -0
- package/dist/components/SimpleNode.svelte +447 -0
- package/dist/components/SimpleNode.svelte.d.ts +24 -0
- package/dist/components/SquareNode.svelte +346 -0
- package/dist/components/SquareNode.svelte.d.ts +24 -0
- package/dist/components/StatusIcon.svelte +112 -0
- package/dist/components/StatusIcon.svelte.d.ts +10 -0
- package/dist/components/StatusLabel.svelte +33 -0
- package/dist/components/StatusLabel.svelte.d.ts +7 -0
- package/dist/components/ToolNode.svelte +385 -0
- package/dist/components/ToolNode.svelte.d.ts +36 -0
- package/dist/components/UniversalNode.svelte +126 -0
- package/dist/components/UniversalNode.svelte.d.ts +15 -0
- package/dist/components/WorkflowEditor.svelte +871 -528
- package/dist/components/WorkflowEditor.svelte.d.ts +15 -5
- package/dist/components/WorkflowNode.svelte +428 -542
- package/dist/components/WorkflowNode.svelte.d.ts +7 -3
- package/dist/config/apiConfig.d.ts +33 -0
- package/dist/config/apiConfig.js +39 -0
- package/dist/config/defaultPortConfig.d.ts +6 -0
- package/dist/config/defaultPortConfig.js +192 -0
- package/dist/config/demo.d.ts +58 -0
- package/dist/config/demo.js +142 -0
- package/dist/config/endpoints.d.ts +106 -0
- package/dist/config/endpoints.js +128 -0
- package/dist/data/samples.d.ts +38 -4
- package/dist/data/samples.js +2789 -737
- package/dist/examples/adapter-usage.d.ts +4 -4
- package/dist/examples/adapter-usage.js +21 -26
- package/dist/examples/api-client-usage.d.ts +6 -6
- package/dist/examples/api-client-usage.js +55 -54
- package/dist/index.d.ts +23 -15
- package/dist/index.js +23 -15
- package/dist/mocks/app-environment.d.ts +8 -0
- package/dist/mocks/app-environment.js +16 -0
- package/dist/mocks/app-forms.d.ts +2 -0
- package/dist/mocks/app-forms.js +21 -0
- package/dist/mocks/app-navigation.d.ts +5 -0
- package/dist/mocks/app-navigation.js +34 -0
- package/dist/mocks/app-stores.d.ts +14 -0
- package/dist/mocks/app-stores.js +26 -0
- package/dist/services/api.d.ts +13 -3
- package/dist/services/api.js +91 -36
- package/dist/services/globalSave.d.ts +20 -0
- package/dist/services/globalSave.js +165 -0
- package/dist/services/nodeExecutionService.d.ts +63 -0
- package/dist/services/nodeExecutionService.js +261 -0
- package/dist/services/portConfigApi.d.ts +14 -0
- package/dist/services/portConfigApi.js +69 -0
- package/dist/services/toastService.d.ts +147 -0
- package/dist/services/toastService.js +235 -0
- package/dist/services/workflowStorage.d.ts +2 -2
- package/dist/services/workflowStorage.js +10 -10
- package/dist/stores/workflowStore.d.ts +53 -0
- package/dist/stores/workflowStore.js +264 -0
- package/dist/styles/base.css +896 -363
- package/dist/svelte-app.d.ts +52 -5
- package/dist/svelte-app.js +128 -6
- package/dist/types/config.d.ts +291 -0
- package/dist/types/config.js +4 -0
- package/dist/types/index.d.ts +231 -19
- package/dist/types/index.js +1 -1
- package/dist/utils/colors.d.ts +67 -33
- package/dist/utils/colors.js +183 -118
- package/dist/utils/config.d.ts +41 -0
- package/dist/utils/config.js +248 -0
- package/dist/utils/connections.d.ts +40 -3
- package/dist/utils/connections.js +115 -44
- package/dist/utils/icons.d.ts +1 -1
- package/dist/utils/icons.js +71 -70
- package/dist/utils/nodeStatus.d.ts +53 -0
- package/dist/utils/nodeStatus.js +183 -0
- package/dist/utils/nodeTypes.d.ts +57 -0
- package/dist/utils/nodeTypes.js +109 -0
- package/dist/utils/nodeWrapper.d.ts +39 -0
- package/dist/utils/nodeWrapper.js +62 -0
- package/package.json +129 -97
- package/dist/components/Node.svelte +0 -38
- package/dist/components/Node.svelte.d.ts +0 -4
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock for $app/stores
|
|
3
|
+
* Provides minimal implementations for SvelteKit stores in library context
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { writable } from 'svelte/store';
|
|
7
|
+
|
|
8
|
+
// Mock page store
|
|
9
|
+
export const page = writable({
|
|
10
|
+
url: new URL('http://localhost:3000'),
|
|
11
|
+
params: {},
|
|
12
|
+
route: { id: null },
|
|
13
|
+
status: 200,
|
|
14
|
+
error: null,
|
|
15
|
+
data: {},
|
|
16
|
+
form: null
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Mock navigating store
|
|
20
|
+
export const navigating = writable(null);
|
|
21
|
+
|
|
22
|
+
// Mock updated store
|
|
23
|
+
export const updated = writable(false);
|
|
24
|
+
|
|
25
|
+
// Mock preloadData function
|
|
26
|
+
export const preloadData = async () => ({});
|
package/dist/services/api.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Client-side API service for FlowDrop
|
|
3
|
-
* Provides methods to interact with the backend APIs
|
|
3
|
+
* Provides methods to interact with the backend APIs using configurable endpoints
|
|
4
4
|
*/
|
|
5
|
-
import type { NodeMetadata, Workflow } from
|
|
5
|
+
import type { NodeMetadata, Workflow } from '../types/index.js';
|
|
6
|
+
import type { EndpointConfig } from '../config/endpoints.js';
|
|
6
7
|
/**
|
|
7
|
-
* Set the
|
|
8
|
+
* Set the endpoint configuration at runtime
|
|
9
|
+
*/
|
|
10
|
+
export declare function setEndpointConfig(config: EndpointConfig): void;
|
|
11
|
+
/**
|
|
12
|
+
* Get the current endpoint configuration
|
|
13
|
+
*/
|
|
14
|
+
export declare function getEndpointConfig(): EndpointConfig | null;
|
|
15
|
+
/**
|
|
16
|
+
* Set the API base URL (deprecated - use setEndpointConfig instead)
|
|
17
|
+
* @deprecated Use setEndpointConfig() with a full EndpointConfig object instead
|
|
8
18
|
*/
|
|
9
19
|
export declare function setApiBaseUrl(url: string): void;
|
|
10
20
|
/**
|
package/dist/services/api.js
CHANGED
|
@@ -1,24 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Client-side API service for FlowDrop
|
|
3
|
-
* Provides methods to interact with the backend APIs
|
|
3
|
+
* Provides methods to interact with the backend APIs using configurable endpoints
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import { buildEndpointUrl, getEndpointMethod, getEndpointHeaders } from '../config/endpoints.js';
|
|
6
|
+
let endpointConfig = null;
|
|
6
7
|
/**
|
|
7
|
-
* Set the
|
|
8
|
+
* Set the endpoint configuration at runtime
|
|
9
|
+
*/
|
|
10
|
+
export function setEndpointConfig(config) {
|
|
11
|
+
endpointConfig = config;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get the current endpoint configuration
|
|
15
|
+
*/
|
|
16
|
+
export function getEndpointConfig() {
|
|
17
|
+
return endpointConfig;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Set the API base URL (deprecated - use setEndpointConfig instead)
|
|
21
|
+
* @deprecated Use setEndpointConfig() with a full EndpointConfig object instead
|
|
8
22
|
*/
|
|
9
23
|
export function setApiBaseUrl(url) {
|
|
10
|
-
|
|
24
|
+
console.warn('⚠️ setApiBaseUrl() is deprecated. Use setEndpointConfig() with a full EndpointConfig object instead.');
|
|
25
|
+
if (!endpointConfig) {
|
|
26
|
+
// Dynamic import for backward compatibility
|
|
27
|
+
import('../config/endpoints.js')
|
|
28
|
+
.then(({ createEndpointConfig }) => {
|
|
29
|
+
endpointConfig = createEndpointConfig(url);
|
|
30
|
+
})
|
|
31
|
+
.catch((error) => {
|
|
32
|
+
// Failed to load endpoint config
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
endpointConfig.baseUrl = url.replace(/\/$/, '');
|
|
37
|
+
}
|
|
11
38
|
}
|
|
12
39
|
/**
|
|
13
|
-
* Generic API request helper
|
|
40
|
+
* Generic API request helper with endpoint configuration
|
|
14
41
|
*/
|
|
15
|
-
async function apiRequest(
|
|
42
|
+
async function apiRequest(endpointKey, endpointPath, params, options = {}) {
|
|
43
|
+
if (!endpointConfig) {
|
|
44
|
+
throw new Error('Endpoint configuration not set. Call setEndpointConfig() first.');
|
|
45
|
+
}
|
|
16
46
|
try {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
47
|
+
const url = buildEndpointUrl(endpointConfig, endpointPath, params);
|
|
48
|
+
const method = getEndpointMethod(endpointConfig, endpointKey);
|
|
49
|
+
const headers = getEndpointHeaders(endpointConfig, endpointKey);
|
|
50
|
+
const response = await fetch(url, {
|
|
51
|
+
method,
|
|
52
|
+
headers,
|
|
22
53
|
...options
|
|
23
54
|
});
|
|
24
55
|
const data = await response.json();
|
|
@@ -28,7 +59,6 @@ async function apiRequest(endpoint, options = {}) {
|
|
|
28
59
|
return data;
|
|
29
60
|
}
|
|
30
61
|
catch (error) {
|
|
31
|
-
console.error(`API request failed for ${endpoint}:`, error);
|
|
32
62
|
throw error;
|
|
33
63
|
}
|
|
34
64
|
}
|
|
@@ -40,25 +70,31 @@ export const nodeApi = {
|
|
|
40
70
|
* Get all node types with optional filtering
|
|
41
71
|
*/
|
|
42
72
|
async getNodes(options) {
|
|
73
|
+
if (!endpointConfig) {
|
|
74
|
+
throw new Error('Endpoint configuration not set');
|
|
75
|
+
}
|
|
43
76
|
const params = new URLSearchParams();
|
|
44
77
|
if (options?.category)
|
|
45
|
-
params.append(
|
|
78
|
+
params.append('category', options.category);
|
|
46
79
|
if (options?.search)
|
|
47
|
-
params.append(
|
|
80
|
+
params.append('search', options.search);
|
|
48
81
|
if (options?.limit)
|
|
49
|
-
params.append(
|
|
82
|
+
params.append('limit', options.limit.toString());
|
|
50
83
|
if (options?.offset)
|
|
51
|
-
params.append(
|
|
52
|
-
const response = await apiRequest(
|
|
84
|
+
params.append('offset', options.offset.toString());
|
|
85
|
+
const response = await apiRequest('nodes.list', endpointConfig.endpoints.nodes.list + '?' + params.toString());
|
|
53
86
|
return response.data || [];
|
|
54
87
|
},
|
|
55
88
|
/**
|
|
56
89
|
* Get a specific node type by ID
|
|
57
90
|
*/
|
|
58
91
|
async getNode(id) {
|
|
59
|
-
|
|
92
|
+
if (!endpointConfig) {
|
|
93
|
+
throw new Error('Endpoint configuration not set');
|
|
94
|
+
}
|
|
95
|
+
const response = await apiRequest('nodes.get', endpointConfig.endpoints.nodes.get, { id });
|
|
60
96
|
if (!response.data) {
|
|
61
|
-
throw new Error(
|
|
97
|
+
throw new Error('Node not found');
|
|
62
98
|
}
|
|
63
99
|
return response.data;
|
|
64
100
|
}
|
|
@@ -71,23 +107,29 @@ export const workflowApi = {
|
|
|
71
107
|
* Get all workflows with optional filtering
|
|
72
108
|
*/
|
|
73
109
|
async getWorkflows(options) {
|
|
110
|
+
if (!endpointConfig) {
|
|
111
|
+
throw new Error('Endpoint configuration not set');
|
|
112
|
+
}
|
|
74
113
|
const params = new URLSearchParams();
|
|
75
114
|
if (options?.search)
|
|
76
|
-
params.append(
|
|
115
|
+
params.append('search', options.search);
|
|
77
116
|
if (options?.limit)
|
|
78
|
-
params.append(
|
|
117
|
+
params.append('limit', options.limit.toString());
|
|
79
118
|
if (options?.offset)
|
|
80
|
-
params.append(
|
|
81
|
-
const response = await apiRequest(
|
|
119
|
+
params.append('offset', options.offset.toString());
|
|
120
|
+
const response = await apiRequest('workflows.list', endpointConfig.endpoints.workflows.list + '?' + params.toString());
|
|
82
121
|
return response.data || [];
|
|
83
122
|
},
|
|
84
123
|
/**
|
|
85
124
|
* Get a specific workflow by ID
|
|
86
125
|
*/
|
|
87
126
|
async getWorkflow(id) {
|
|
88
|
-
|
|
127
|
+
if (!endpointConfig) {
|
|
128
|
+
throw new Error('Endpoint configuration not set');
|
|
129
|
+
}
|
|
130
|
+
const response = await apiRequest('workflows.get', endpointConfig.endpoints.workflows.get, { id });
|
|
89
131
|
if (!response.data) {
|
|
90
|
-
throw new Error(
|
|
132
|
+
throw new Error('Workflow not found');
|
|
91
133
|
}
|
|
92
134
|
return response.data;
|
|
93
135
|
},
|
|
@@ -95,12 +137,15 @@ export const workflowApi = {
|
|
|
95
137
|
* Create a new workflow
|
|
96
138
|
*/
|
|
97
139
|
async createWorkflow(workflow) {
|
|
98
|
-
|
|
99
|
-
|
|
140
|
+
if (!endpointConfig) {
|
|
141
|
+
throw new Error('Endpoint configuration not set');
|
|
142
|
+
}
|
|
143
|
+
const response = await apiRequest('workflows.create', endpointConfig.endpoints.workflows.create, undefined, {
|
|
144
|
+
method: 'POST',
|
|
100
145
|
body: JSON.stringify(workflow)
|
|
101
146
|
});
|
|
102
147
|
if (!response.data) {
|
|
103
|
-
throw new Error(
|
|
148
|
+
throw new Error('Failed to create workflow');
|
|
104
149
|
}
|
|
105
150
|
return response.data;
|
|
106
151
|
},
|
|
@@ -108,12 +153,15 @@ export const workflowApi = {
|
|
|
108
153
|
* Update an existing workflow
|
|
109
154
|
*/
|
|
110
155
|
async updateWorkflow(id, workflow) {
|
|
111
|
-
|
|
112
|
-
|
|
156
|
+
if (!endpointConfig) {
|
|
157
|
+
throw new Error('Endpoint configuration not set');
|
|
158
|
+
}
|
|
159
|
+
const response = await apiRequest('workflows.update', endpointConfig.endpoints.workflows.update, { id }, {
|
|
160
|
+
method: 'PUT',
|
|
113
161
|
body: JSON.stringify(workflow)
|
|
114
162
|
});
|
|
115
163
|
if (!response.data) {
|
|
116
|
-
throw new Error(
|
|
164
|
+
throw new Error('Failed to update workflow');
|
|
117
165
|
}
|
|
118
166
|
return response.data;
|
|
119
167
|
},
|
|
@@ -121,20 +169,27 @@ export const workflowApi = {
|
|
|
121
169
|
* Delete a workflow
|
|
122
170
|
*/
|
|
123
171
|
async deleteWorkflow(id) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
172
|
+
if (!endpointConfig) {
|
|
173
|
+
throw new Error('Endpoint configuration not set');
|
|
174
|
+
}
|
|
175
|
+
await apiRequest('workflows.delete', endpointConfig.endpoints.workflows.delete, { id }, { method: 'DELETE' });
|
|
127
176
|
},
|
|
128
177
|
/**
|
|
129
178
|
* Save workflow (create or update)
|
|
130
179
|
*/
|
|
131
180
|
async saveWorkflow(workflow) {
|
|
132
|
-
if
|
|
133
|
-
|
|
181
|
+
// Check if this is an existing workflow by looking for a valid ID
|
|
182
|
+
// Valid IDs should not be a UUID (which indicates a new workflow)
|
|
183
|
+
const isExistingWorkflow = workflow.id &&
|
|
184
|
+
workflow.id.length > 0 &&
|
|
185
|
+
!workflow.id.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
|
|
186
|
+
if (isExistingWorkflow) {
|
|
187
|
+
// Update existing workflow
|
|
134
188
|
return this.updateWorkflow(workflow.id, workflow);
|
|
135
189
|
}
|
|
136
190
|
else {
|
|
137
191
|
// Create new workflow
|
|
192
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
138
193
|
const { id, ...workflowData } = workflow;
|
|
139
194
|
return this.createWorkflow(workflowData);
|
|
140
195
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Save Service
|
|
3
|
+
* Provides save and export functionality that can be accessed from anywhere in the app
|
|
4
|
+
* This allows the main navbar to save workflows without being tied to a specific component
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Global save function that can be called from anywhere
|
|
8
|
+
* Uses the current workflow from the global store
|
|
9
|
+
*/
|
|
10
|
+
export declare function globalSaveWorkflow(): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Global export function that can be called from anywhere
|
|
13
|
+
* Uses the current workflow from the global store
|
|
14
|
+
*/
|
|
15
|
+
export declare function globalExportWorkflow(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Initialize global save functions on window object for external access
|
|
18
|
+
* This allows the functions to be called from anywhere in the application
|
|
19
|
+
*/
|
|
20
|
+
export declare function initializeGlobalSave(): void;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Save Service
|
|
3
|
+
* Provides save and export functionality that can be accessed from anywhere in the app
|
|
4
|
+
* This allows the main navbar to save workflows without being tied to a specific component
|
|
5
|
+
*/
|
|
6
|
+
import { get } from 'svelte/store';
|
|
7
|
+
import { workflowStore } from '../stores/workflowStore.js';
|
|
8
|
+
import { workflowApi, setEndpointConfig } from './api.js';
|
|
9
|
+
import { createEndpointConfig } from '../config/endpoints.js';
|
|
10
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
11
|
+
import { apiToasts, workflowToasts, dismissToast } from './toastService.js';
|
|
12
|
+
/**
|
|
13
|
+
* Ensure API configuration is initialized
|
|
14
|
+
* This is needed when the global save function is called from the layout component
|
|
15
|
+
* which doesn't initialize the API configuration like the App component does
|
|
16
|
+
*/
|
|
17
|
+
async function ensureApiConfiguration() {
|
|
18
|
+
// Check if we need to initialize the API configuration
|
|
19
|
+
// We'll check if the endpointConfig is already set by importing the api module
|
|
20
|
+
try {
|
|
21
|
+
// Import the api module to check if endpointConfig is already set
|
|
22
|
+
const { getEndpointConfig } = await import('./api.js');
|
|
23
|
+
// Try to get the current configuration
|
|
24
|
+
const currentConfig = getEndpointConfig();
|
|
25
|
+
if (currentConfig && currentConfig.baseUrl) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
// Could not check existing API configuration, initializing
|
|
31
|
+
}
|
|
32
|
+
// API configuration is not initialized, so let's initialize it
|
|
33
|
+
// Use the same environment variable priority as the App component
|
|
34
|
+
// Prioritize VITE_API_BASE_URL since it's configured correctly
|
|
35
|
+
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL ||
|
|
36
|
+
import.meta.env.VITE_DRUPAL_API_URL ||
|
|
37
|
+
import.meta.env.VITE_FLOWDROP_API_URL ||
|
|
38
|
+
(() => {
|
|
39
|
+
// If we're in development (localhost:5173), use relative path
|
|
40
|
+
if (window.location.hostname === 'localhost' && window.location.port === '5173') {
|
|
41
|
+
return '/api/flowdrop';
|
|
42
|
+
}
|
|
43
|
+
// Otherwise, use the current domain
|
|
44
|
+
return `${window.location.protocol}//${window.location.host}/api/flowdrop`;
|
|
45
|
+
})();
|
|
46
|
+
const config = createEndpointConfig(apiBaseUrl, {
|
|
47
|
+
auth: {
|
|
48
|
+
type: 'none' // No authentication for now
|
|
49
|
+
},
|
|
50
|
+
timeout: 10000, // 10 second timeout
|
|
51
|
+
retry: {
|
|
52
|
+
enabled: true,
|
|
53
|
+
maxAttempts: 2,
|
|
54
|
+
delay: 1000,
|
|
55
|
+
backoff: 'exponential'
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
setEndpointConfig(config);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Global save function that can be called from anywhere
|
|
62
|
+
* Uses the current workflow from the global store
|
|
63
|
+
*/
|
|
64
|
+
export async function globalSaveWorkflow() {
|
|
65
|
+
let loadingToast;
|
|
66
|
+
try {
|
|
67
|
+
// Show loading toast
|
|
68
|
+
loadingToast = apiToasts.loading('Saving workflow');
|
|
69
|
+
// Ensure API configuration is initialized
|
|
70
|
+
await ensureApiConfiguration();
|
|
71
|
+
// Get current workflow from global store
|
|
72
|
+
const currentWorkflow = get(workflowStore);
|
|
73
|
+
if (!currentWorkflow) {
|
|
74
|
+
if (loadingToast)
|
|
75
|
+
dismissToast(loadingToast);
|
|
76
|
+
apiToasts.error('Save workflow', 'No workflow to save');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Determine the workflow ID
|
|
80
|
+
let workflowId;
|
|
81
|
+
if (currentWorkflow.id) {
|
|
82
|
+
workflowId = currentWorkflow.id;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
workflowId = uuidv4();
|
|
86
|
+
}
|
|
87
|
+
// Create workflow object for saving
|
|
88
|
+
const finalWorkflow = {
|
|
89
|
+
id: workflowId,
|
|
90
|
+
name: currentWorkflow.name || 'Untitled Workflow',
|
|
91
|
+
nodes: currentWorkflow.nodes || [],
|
|
92
|
+
edges: currentWorkflow.edges || [],
|
|
93
|
+
metadata: {
|
|
94
|
+
version: '1.0.0',
|
|
95
|
+
createdAt: currentWorkflow.metadata?.createdAt || new Date().toISOString(),
|
|
96
|
+
updatedAt: new Date().toISOString()
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const savedWorkflow = await workflowApi.saveWorkflow(finalWorkflow);
|
|
100
|
+
// Dismiss loading toast and show success toast
|
|
101
|
+
if (loadingToast)
|
|
102
|
+
dismissToast(loadingToast);
|
|
103
|
+
workflowToasts.saved(finalWorkflow.name);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
// Dismiss loading toast and show error toast
|
|
107
|
+
if (loadingToast)
|
|
108
|
+
dismissToast(loadingToast);
|
|
109
|
+
apiToasts.error('Save workflow', error instanceof Error ? error.message : 'Unknown error');
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Global export function that can be called from anywhere
|
|
115
|
+
* Uses the current workflow from the global store
|
|
116
|
+
*/
|
|
117
|
+
export async function globalExportWorkflow() {
|
|
118
|
+
try {
|
|
119
|
+
// Get current workflow from global store
|
|
120
|
+
const currentWorkflow = get(workflowStore);
|
|
121
|
+
if (!currentWorkflow) {
|
|
122
|
+
apiToasts.error('Export workflow', 'No workflow to export');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Create workflow object for export
|
|
126
|
+
const finalWorkflow = {
|
|
127
|
+
id: currentWorkflow.id || 'untitled-workflow',
|
|
128
|
+
name: currentWorkflow.name || 'Untitled Workflow',
|
|
129
|
+
nodes: currentWorkflow.nodes || [],
|
|
130
|
+
edges: currentWorkflow.edges || [],
|
|
131
|
+
metadata: {
|
|
132
|
+
version: '1.0.0',
|
|
133
|
+
createdAt: currentWorkflow.metadata?.createdAt || new Date().toISOString(),
|
|
134
|
+
updatedAt: new Date().toISOString()
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
// Create and download the file
|
|
138
|
+
const dataStr = JSON.stringify(finalWorkflow, null, 2);
|
|
139
|
+
const dataBlob = new Blob([dataStr], { type: 'application/json' });
|
|
140
|
+
const url = URL.createObjectURL(dataBlob);
|
|
141
|
+
const link = document.createElement('a');
|
|
142
|
+
link.href = url;
|
|
143
|
+
link.download = `${finalWorkflow.name}.json`;
|
|
144
|
+
link.click();
|
|
145
|
+
URL.revokeObjectURL(url);
|
|
146
|
+
// Show success toast
|
|
147
|
+
workflowToasts.exported(finalWorkflow.name);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
// Export failed
|
|
151
|
+
apiToasts.error('Export workflow', error instanceof Error ? error.message : 'Unknown error');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Initialize global save functions on window object for external access
|
|
156
|
+
* This allows the functions to be called from anywhere in the application
|
|
157
|
+
*/
|
|
158
|
+
export function initializeGlobalSave() {
|
|
159
|
+
if (typeof window !== 'undefined') {
|
|
160
|
+
// @ts-ignore - Adding to window for external access
|
|
161
|
+
window.flowdropGlobalSave = globalSaveWorkflow;
|
|
162
|
+
// @ts-ignore - Adding to window for external access
|
|
163
|
+
window.flowdropGlobalExport = globalExportWorkflow;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node Execution Service
|
|
3
|
+
* Handles fetching and managing node execution information from the backend
|
|
4
|
+
*/
|
|
5
|
+
import type { NodeExecutionInfo } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Service for managing node execution information
|
|
8
|
+
*/
|
|
9
|
+
export declare class NodeExecutionService {
|
|
10
|
+
private static instance;
|
|
11
|
+
private cache;
|
|
12
|
+
private cacheTimeout;
|
|
13
|
+
private lastFetch;
|
|
14
|
+
private apiUnavailable;
|
|
15
|
+
private apiUnavailableUntil;
|
|
16
|
+
private constructor();
|
|
17
|
+
static getInstance(): NodeExecutionService;
|
|
18
|
+
/**
|
|
19
|
+
* Get execution information for a specific node from pipeline data
|
|
20
|
+
*/
|
|
21
|
+
getNodeExecutionInfo(nodeId: string, pipelineId?: string): Promise<NodeExecutionInfo | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Get execution information for multiple nodes from pipeline data
|
|
24
|
+
*/
|
|
25
|
+
getMultipleNodeExecutionInfo(nodeIds: string[], pipelineId?: string): Promise<Record<string, NodeExecutionInfo>>;
|
|
26
|
+
/**
|
|
27
|
+
* Get all node execution counts
|
|
28
|
+
*/
|
|
29
|
+
getAllNodeExecutionCounts(): Promise<Record<string, number>>;
|
|
30
|
+
/**
|
|
31
|
+
* Get cached execution info for a node
|
|
32
|
+
*/
|
|
33
|
+
getCachedNodeExecutionInfo(nodeId: string): NodeExecutionInfo | null;
|
|
34
|
+
/**
|
|
35
|
+
* Clear cache for a specific node
|
|
36
|
+
*/
|
|
37
|
+
clearNodeCache(nodeId: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Clear all cache
|
|
40
|
+
*/
|
|
41
|
+
clearAllCache(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Check if cache is stale
|
|
44
|
+
*/
|
|
45
|
+
isCacheStale(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Update execution info for a node (for real-time updates)
|
|
48
|
+
*/
|
|
49
|
+
updateNodeExecutionInfo(nodeId: string, executionInfo: Partial<NodeExecutionInfo>): void;
|
|
50
|
+
/**
|
|
51
|
+
* Map job status to execution status
|
|
52
|
+
*/
|
|
53
|
+
private mapJobStatusToExecutionStatus;
|
|
54
|
+
/**
|
|
55
|
+
* Batch update execution info for multiple nodes
|
|
56
|
+
*/
|
|
57
|
+
updateMultipleNodeExecutionInfo(updates: Record<string, Partial<NodeExecutionInfo>>): void;
|
|
58
|
+
/**
|
|
59
|
+
* Reset API availability status (useful for testing or when API becomes available)
|
|
60
|
+
*/
|
|
61
|
+
resetApiAvailability(): void;
|
|
62
|
+
}
|
|
63
|
+
export declare const nodeExecutionService: NodeExecutionService;
|