@genfeedai/workflow-ui 0.2.2 → 0.2.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.
- package/README.md +11 -33
- package/dist/canvas.d.ts +22 -22
- package/dist/canvas.mjs +16 -17
- package/dist/{chunk-WBR34V4L.mjs → chunk-2FUPL67V.mjs} +1593 -1045
- package/dist/{chunk-4VEN4UN7.mjs → chunk-53XDE62A.mjs} +818 -623
- package/dist/{chunk-PCIWWD37.mjs → chunk-7LV4UAUS.mjs} +19 -19
- package/dist/{chunk-7SKSRSS7.mjs → chunk-B4EAAKYF.mjs} +16 -16
- package/dist/{chunk-ZJD5WMR3.mjs → chunk-C6MQBJFC.mjs} +45 -13
- package/dist/{chunk-7H3WJJYS.mjs → chunk-ESVULCFY.mjs} +12 -6
- package/dist/{chunk-GWBGK3KL.mjs → chunk-FWJIAW2E.mjs} +82 -47
- package/dist/{chunk-R727OFBR.mjs → chunk-GPYIIWD5.mjs} +404 -350
- package/dist/{chunk-OQREHJXK.mjs → chunk-IYFWAJBB.mjs} +208 -203
- package/dist/{chunk-2JQSKIWR.mjs → chunk-MGLAKMDP.mjs} +24 -23
- package/dist/{chunk-LT3ZJJL6.mjs → chunk-OJWVEEMM.mjs} +497 -399
- package/dist/{chunk-ZD2BADZO.mjs → chunk-ORVDYXDP.mjs} +221 -175
- package/dist/{chunk-CV4M7CNU.mjs → chunk-QQVHGJ2G.mjs} +149 -142
- package/dist/{chunk-6PSJTBNV.mjs → chunk-U4QPE4CY.mjs} +387 -347
- package/dist/{chunk-EFXQT23N.mjs → chunk-VVQ4CH77.mjs} +5 -5
- package/dist/{chunk-VRN3UWE5.mjs → chunk-XRC3O5GK.mjs} +73 -73
- package/dist/{chunk-FT33LFII.mjs → chunk-YUIK4AHM.mjs} +1 -1
- package/dist/{chunk-JT4Y5H3U.mjs → chunk-ZSITTZ4S.mjs} +630 -569
- package/dist/hooks.d.ts +37 -37
- package/dist/hooks.mjs +10 -10
- package/dist/index.d.ts +26 -11
- package/dist/index.mjs +99 -20
- package/dist/lib.d.ts +203 -203
- package/dist/lib.mjs +228 -199
- package/dist/nodes.d.ts +2 -2
- package/dist/nodes.mjs +12 -13
- package/dist/panels.d.ts +2 -3
- package/dist/panels.mjs +3 -3
- package/dist/provider.d.ts +2 -2
- package/dist/provider.mjs +2 -2
- package/dist/stores.d.ts +5 -5
- package/dist/stores.mjs +5 -5
- package/dist/toolbar.d.ts +42 -24
- package/dist/toolbar.mjs +4 -5
- package/dist/ui.d.ts +2 -2
- package/dist/ui.mjs +2 -2
- package/dist/{useCommentNavigation-BakbiiIc.d.ts → useRequiredInputs-ByoIS-fT.d.ts} +160 -160
- package/dist/{promptLibraryStore-Dl3Q3cP6.d.ts → workflowStore-Bsz0nd5c.d.ts} +368 -368
- package/dist/workflowStore-N2F7WIG3.mjs +2 -0
- package/package.json +79 -77
- package/src/styles/workflow-ui.css +56 -19
- package/dist/chunk-OY7BRSGG.mjs +0 -60
- package/dist/workflowStore-UAAKOOIK.mjs +0 -2
- package/dist/{types-IEKYuYhu.d.ts → types-CRXJnajq.d.ts} +1 -1
|
@@ -1,105 +1,101 @@
|
|
|
1
|
-
import { useWorkflowStore } from './chunk-
|
|
1
|
+
import { useWorkflowStore } from './chunk-GPYIIWD5.mjs';
|
|
2
2
|
import { create } from 'zustand';
|
|
3
3
|
import { ProviderTypeEnum, NodeStatusEnum } from '@genfeedai/types';
|
|
4
4
|
|
|
5
5
|
var notificationId = 0;
|
|
6
6
|
var useUIStore = create((set) => ({
|
|
7
|
-
showPalette: true,
|
|
8
|
-
showMinimap: true,
|
|
9
|
-
showAIGenerator: false,
|
|
10
|
-
showDebugPanel: false,
|
|
11
|
-
selectedNodeId: null,
|
|
12
|
-
selectedEdgeId: null,
|
|
13
|
-
highlightedNodeIds: [],
|
|
14
7
|
activeModal: null,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
set((state) => ({ showAIGenerator: !state.showAIGenerator }));
|
|
28
|
-
},
|
|
29
|
-
toggleDebugPanel: () => {
|
|
30
|
-
set((state) => ({ showDebugPanel: !state.showDebugPanel }));
|
|
31
|
-
},
|
|
32
|
-
setShowDebugPanel: (show) => {
|
|
33
|
-
set({ showDebugPanel: show });
|
|
34
|
-
},
|
|
35
|
-
selectNode: (nodeId) => {
|
|
36
|
-
set({ selectedNodeId: nodeId, selectedEdgeId: null });
|
|
37
|
-
},
|
|
38
|
-
selectEdge: (edgeId) => {
|
|
39
|
-
set({ selectedEdgeId: edgeId, selectedNodeId: null });
|
|
40
|
-
},
|
|
41
|
-
setHighlightedNodeIds: (ids) => {
|
|
42
|
-
set({ highlightedNodeIds: ids });
|
|
8
|
+
addNotification: (notification) => {
|
|
9
|
+
const id = `notification-${++notificationId}`;
|
|
10
|
+
set((state) => ({
|
|
11
|
+
notifications: [...state.notifications, { ...notification, id }]
|
|
12
|
+
}));
|
|
13
|
+
if (notification.duration !== 0) {
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
set((state) => ({
|
|
16
|
+
notifications: state.notifications.filter((n) => n.id !== id)
|
|
17
|
+
}));
|
|
18
|
+
}, notification.duration ?? 5e3);
|
|
19
|
+
}
|
|
43
20
|
},
|
|
44
|
-
|
|
45
|
-
set({
|
|
21
|
+
closeConnectionDropMenu: () => {
|
|
22
|
+
set({ connectionDropMenu: null });
|
|
46
23
|
},
|
|
47
24
|
closeModal: () => {
|
|
48
25
|
set({ activeModal: null });
|
|
49
26
|
},
|
|
27
|
+
closeNodeDetailModal: () => {
|
|
28
|
+
set({
|
|
29
|
+
activeModal: null,
|
|
30
|
+
nodeDetailActiveTab: "preview",
|
|
31
|
+
nodeDetailNodeId: null,
|
|
32
|
+
nodeDetailStartIndex: 0
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
connectionDropMenu: null,
|
|
36
|
+
highlightedNodeIds: [],
|
|
37
|
+
nodeDetailActiveTab: "preview",
|
|
38
|
+
nodeDetailNodeId: null,
|
|
39
|
+
nodeDetailStartIndex: 0,
|
|
40
|
+
notifications: [],
|
|
50
41
|
openConnectionDropMenu: (params) => {
|
|
51
42
|
set({ connectionDropMenu: params });
|
|
52
43
|
},
|
|
53
|
-
|
|
54
|
-
set({
|
|
44
|
+
openModal: (modal) => {
|
|
45
|
+
set({ activeModal: modal });
|
|
55
46
|
},
|
|
56
47
|
openNodeDetailModal: (nodeId, tab = "preview", startIndex = 0) => {
|
|
57
48
|
set({
|
|
58
49
|
activeModal: "nodeDetail",
|
|
59
|
-
nodeDetailNodeId: nodeId,
|
|
60
50
|
nodeDetailActiveTab: tab,
|
|
51
|
+
nodeDetailNodeId: nodeId,
|
|
61
52
|
nodeDetailStartIndex: startIndex
|
|
62
53
|
});
|
|
63
54
|
},
|
|
64
|
-
|
|
65
|
-
set({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
55
|
+
removeNotification: (id) => {
|
|
56
|
+
set((state) => ({
|
|
57
|
+
notifications: state.notifications.filter((n) => n.id !== id)
|
|
58
|
+
}));
|
|
59
|
+
},
|
|
60
|
+
selectEdge: (edgeId) => {
|
|
61
|
+
set({ selectedEdgeId: edgeId, selectedNodeId: null });
|
|
62
|
+
},
|
|
63
|
+
selectedEdgeId: null,
|
|
64
|
+
selectedNodeId: null,
|
|
65
|
+
selectNode: (nodeId) => {
|
|
66
|
+
set({ selectedEdgeId: null, selectedNodeId: nodeId });
|
|
67
|
+
},
|
|
68
|
+
setHighlightedNodeIds: (ids) => {
|
|
69
|
+
set({ highlightedNodeIds: ids });
|
|
71
70
|
},
|
|
72
71
|
setNodeDetailTab: (tab) => {
|
|
73
72
|
set({ nodeDetailActiveTab: tab });
|
|
74
73
|
},
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
set((state) => ({
|
|
78
|
-
notifications: [...state.notifications, { ...notification, id }]
|
|
79
|
-
}));
|
|
80
|
-
if (notification.duration !== 0) {
|
|
81
|
-
setTimeout(() => {
|
|
82
|
-
set((state) => ({
|
|
83
|
-
notifications: state.notifications.filter((n) => n.id !== id)
|
|
84
|
-
}));
|
|
85
|
-
}, notification.duration ?? 5e3);
|
|
86
|
-
}
|
|
74
|
+
setShowDebugPanel: (show) => {
|
|
75
|
+
set({ showDebugPanel: show });
|
|
87
76
|
},
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
77
|
+
showAIGenerator: false,
|
|
78
|
+
showDebugPanel: false,
|
|
79
|
+
showMinimap: true,
|
|
80
|
+
showPalette: true,
|
|
81
|
+
toggleAIGenerator: () => {
|
|
82
|
+
set((state) => ({ showAIGenerator: !state.showAIGenerator }));
|
|
83
|
+
},
|
|
84
|
+
toggleDebugPanel: () => {
|
|
85
|
+
set((state) => ({ showDebugPanel: !state.showDebugPanel }));
|
|
86
|
+
},
|
|
87
|
+
toggleMinimap: () => {
|
|
88
|
+
set((state) => ({ showMinimap: !state.showMinimap }));
|
|
89
|
+
},
|
|
90
|
+
togglePalette: () => {
|
|
91
|
+
set((state) => ({ showPalette: !state.showPalette }));
|
|
92
92
|
}
|
|
93
93
|
}));
|
|
94
94
|
var STORAGE_KEY = "genfeed-settings";
|
|
95
95
|
var MAX_RECENT_MODELS = 8;
|
|
96
96
|
var DEFAULT_SETTINGS = {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
fal: { apiKey: null, enabled: false },
|
|
100
|
-
huggingface: { apiKey: null, enabled: false },
|
|
101
|
-
"genfeed-ai": { apiKey: null, enabled: true }
|
|
102
|
-
},
|
|
97
|
+
autoSaveEnabled: true,
|
|
98
|
+
debugMode: false,
|
|
103
99
|
defaults: {
|
|
104
100
|
imageModel: "nano-banana-pro",
|
|
105
101
|
imageProvider: "replicate",
|
|
@@ -107,11 +103,15 @@ var DEFAULT_SETTINGS = {
|
|
|
107
103
|
videoProvider: "replicate"
|
|
108
104
|
},
|
|
109
105
|
edgeStyle: "default",
|
|
110
|
-
showMinimap: true,
|
|
111
|
-
autoSaveEnabled: true,
|
|
112
|
-
recentModels: [],
|
|
113
106
|
hasSeenWelcome: false,
|
|
114
|
-
|
|
107
|
+
providers: {
|
|
108
|
+
fal: { apiKey: null, enabled: false },
|
|
109
|
+
"genfeed-ai": { apiKey: null, enabled: true },
|
|
110
|
+
huggingface: { apiKey: null, enabled: false },
|
|
111
|
+
replicate: { apiKey: null, enabled: true }
|
|
112
|
+
},
|
|
113
|
+
recentModels: [],
|
|
114
|
+
showMinimap: true
|
|
115
115
|
};
|
|
116
116
|
function loadFromStorage() {
|
|
117
117
|
if (typeof window === "undefined") return {};
|
|
@@ -120,14 +120,14 @@ function loadFromStorage() {
|
|
|
120
120
|
if (stored) {
|
|
121
121
|
const parsed = JSON.parse(stored);
|
|
122
122
|
return {
|
|
123
|
-
|
|
123
|
+
autoSaveEnabled: parsed.autoSaveEnabled ?? true,
|
|
124
|
+
debugMode: parsed.debugMode ?? false,
|
|
124
125
|
defaults: { ...DEFAULT_SETTINGS.defaults, ...parsed.defaults },
|
|
125
126
|
edgeStyle: parsed.edgeStyle === "bezier" ? "default" : parsed.edgeStyle ?? DEFAULT_SETTINGS.edgeStyle,
|
|
126
|
-
showMinimap: parsed.showMinimap ?? DEFAULT_SETTINGS.showMinimap,
|
|
127
|
-
autoSaveEnabled: parsed.autoSaveEnabled ?? true,
|
|
128
|
-
recentModels: parsed.recentModels ?? [],
|
|
129
127
|
hasSeenWelcome: parsed.hasSeenWelcome ?? false,
|
|
130
|
-
|
|
128
|
+
providers: { ...DEFAULT_SETTINGS.providers, ...parsed.providers },
|
|
129
|
+
recentModels: parsed.recentModels ?? [],
|
|
130
|
+
showMinimap: parsed.showMinimap ?? DEFAULT_SETTINGS.showMinimap
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
} catch {
|
|
@@ -138,11 +138,12 @@ function saveToStorage(state) {
|
|
|
138
138
|
if (typeof window === "undefined") return;
|
|
139
139
|
try {
|
|
140
140
|
const toSave = {
|
|
141
|
+
autoSaveEnabled: state.autoSaveEnabled,
|
|
142
|
+
debugMode: state.debugMode,
|
|
143
|
+
defaults: state.defaults,
|
|
144
|
+
edgeStyle: state.edgeStyle,
|
|
145
|
+
hasSeenWelcome: state.hasSeenWelcome,
|
|
141
146
|
providers: {
|
|
142
|
-
replicate: {
|
|
143
|
-
apiKey: state.providers.replicate.apiKey,
|
|
144
|
-
enabled: state.providers.replicate.enabled
|
|
145
|
-
},
|
|
146
147
|
fal: {
|
|
147
148
|
apiKey: state.providers.fal.apiKey,
|
|
148
149
|
enabled: state.providers.fal.enabled
|
|
@@ -150,15 +151,14 @@ function saveToStorage(state) {
|
|
|
150
151
|
huggingface: {
|
|
151
152
|
apiKey: state.providers.huggingface.apiKey,
|
|
152
153
|
enabled: state.providers.huggingface.enabled
|
|
154
|
+
},
|
|
155
|
+
replicate: {
|
|
156
|
+
apiKey: state.providers.replicate.apiKey,
|
|
157
|
+
enabled: state.providers.replicate.enabled
|
|
153
158
|
}
|
|
154
159
|
},
|
|
155
|
-
defaults: state.defaults,
|
|
156
|
-
edgeStyle: state.edgeStyle,
|
|
157
|
-
showMinimap: state.showMinimap,
|
|
158
|
-
autoSaveEnabled: state.autoSaveEnabled,
|
|
159
160
|
recentModels: state.recentModels.slice(0, MAX_RECENT_MODELS),
|
|
160
|
-
|
|
161
|
-
debugMode: state.debugMode
|
|
161
|
+
showMinimap: state.showMinimap
|
|
162
162
|
};
|
|
163
163
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
|
|
164
164
|
} catch {
|
|
@@ -174,40 +174,67 @@ var useSettingsStore = create((set, get) => {
|
|
|
174
174
|
});
|
|
175
175
|
};
|
|
176
176
|
return {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
177
|
+
addRecentModel: (model) => {
|
|
178
|
+
setAndPersist((state) => {
|
|
179
|
+
const filtered = state.recentModels.filter(
|
|
180
|
+
(m) => !(m.id === model.id && m.provider === model.provider)
|
|
181
|
+
);
|
|
182
|
+
const newRecentModels = [
|
|
183
|
+
{ ...model, timestamp: Date.now() },
|
|
184
|
+
...filtered
|
|
185
|
+
].slice(0, MAX_RECENT_MODELS);
|
|
186
|
+
return { recentModels: newRecentModels };
|
|
187
|
+
});
|
|
187
188
|
},
|
|
188
|
-
|
|
189
|
+
autoSaveEnabled: initialState.autoSaveEnabled,
|
|
190
|
+
clearAllKeys: () => {
|
|
189
191
|
setAndPersist((state) => ({
|
|
190
192
|
providers: {
|
|
191
|
-
...state.providers,
|
|
192
|
-
[
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
enabled: key ? true : state.providers[provider].enabled
|
|
196
|
-
}
|
|
193
|
+
fal: { ...state.providers.fal, apiKey: null },
|
|
194
|
+
"genfeed-ai": { ...state.providers["genfeed-ai"], apiKey: null },
|
|
195
|
+
huggingface: { ...state.providers.huggingface, apiKey: null },
|
|
196
|
+
replicate: { ...state.providers.replicate, apiKey: null }
|
|
197
197
|
}
|
|
198
198
|
}));
|
|
199
199
|
},
|
|
200
|
-
|
|
200
|
+
clearProviderKey: (provider) => {
|
|
201
201
|
setAndPersist((state) => ({
|
|
202
202
|
providers: {
|
|
203
203
|
...state.providers,
|
|
204
204
|
[provider]: {
|
|
205
205
|
...state.providers[provider],
|
|
206
|
-
|
|
206
|
+
apiKey: null
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
}));
|
|
210
210
|
},
|
|
211
|
+
debugMode: initialState.debugMode,
|
|
212
|
+
defaults: initialState.defaults,
|
|
213
|
+
edgeStyle: initialState.edgeStyle,
|
|
214
|
+
getProviderHeader: (provider) => {
|
|
215
|
+
const state = get();
|
|
216
|
+
const key = state.providers[provider].apiKey;
|
|
217
|
+
if (!key) return {};
|
|
218
|
+
const headerMap = {
|
|
219
|
+
[ProviderTypeEnum.REPLICATE]: "X-Replicate-Key",
|
|
220
|
+
[ProviderTypeEnum.FAL]: "X-Fal-Key",
|
|
221
|
+
[ProviderTypeEnum.HUGGINGFACE]: "X-HF-Key",
|
|
222
|
+
[ProviderTypeEnum.GENFEED_AI]: "X-Genfeed-Key"
|
|
223
|
+
};
|
|
224
|
+
return { [headerMap[provider]]: key };
|
|
225
|
+
},
|
|
226
|
+
hasSeenWelcome: initialState.hasSeenWelcome,
|
|
227
|
+
isProviderConfigured: (provider) => {
|
|
228
|
+
const state = get();
|
|
229
|
+
return !!state.providers[provider].apiKey;
|
|
230
|
+
},
|
|
231
|
+
// API Sync - stubbed as no-ops (consuming app provides real implementations)
|
|
232
|
+
isSyncing: false,
|
|
233
|
+
providers: initialState.providers,
|
|
234
|
+
recentModels: initialState.recentModels,
|
|
235
|
+
setDebugMode: (enabled) => {
|
|
236
|
+
setAndPersist(() => ({ debugMode: enabled }));
|
|
237
|
+
},
|
|
211
238
|
setDefaultModel: (type, model, provider) => {
|
|
212
239
|
setAndPersist((state) => ({
|
|
213
240
|
defaults: {
|
|
@@ -218,96 +245,69 @@ var useSettingsStore = create((set, get) => {
|
|
|
218
245
|
},
|
|
219
246
|
setEdgeStyle: (style) => {
|
|
220
247
|
setAndPersist(() => ({ edgeStyle: style }));
|
|
221
|
-
import('./workflowStore-
|
|
248
|
+
import('./workflowStore-N2F7WIG3.mjs').then(({ useWorkflowStore: useWorkflowStore2 }) => {
|
|
222
249
|
useWorkflowStore2.getState().setEdgeStyle(style);
|
|
223
250
|
});
|
|
224
251
|
},
|
|
225
|
-
|
|
226
|
-
setAndPersist(() => ({
|
|
227
|
-
},
|
|
228
|
-
addRecentModel: (model) => {
|
|
229
|
-
setAndPersist((state) => {
|
|
230
|
-
const filtered = state.recentModels.filter(
|
|
231
|
-
(m) => !(m.id === model.id && m.provider === model.provider)
|
|
232
|
-
);
|
|
233
|
-
const newRecentModels = [{ ...model, timestamp: Date.now() }, ...filtered].slice(
|
|
234
|
-
0,
|
|
235
|
-
MAX_RECENT_MODELS
|
|
236
|
-
);
|
|
237
|
-
return { recentModels: newRecentModels };
|
|
238
|
-
});
|
|
252
|
+
setHasSeenWelcome: (seen) => {
|
|
253
|
+
setAndPersist(() => ({ hasSeenWelcome: seen }));
|
|
239
254
|
},
|
|
240
|
-
|
|
255
|
+
setProviderEnabled: (provider, enabled) => {
|
|
241
256
|
setAndPersist((state) => ({
|
|
242
257
|
providers: {
|
|
243
258
|
...state.providers,
|
|
244
259
|
[provider]: {
|
|
245
260
|
...state.providers[provider],
|
|
246
|
-
|
|
261
|
+
enabled
|
|
247
262
|
}
|
|
248
263
|
}
|
|
249
264
|
}));
|
|
250
265
|
},
|
|
251
|
-
|
|
266
|
+
setProviderKey: (provider, key) => {
|
|
252
267
|
setAndPersist((state) => ({
|
|
253
268
|
providers: {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
269
|
+
...state.providers,
|
|
270
|
+
[provider]: {
|
|
271
|
+
...state.providers[provider],
|
|
272
|
+
apiKey: key,
|
|
273
|
+
enabled: key ? true : state.providers[provider].enabled
|
|
274
|
+
}
|
|
258
275
|
}
|
|
259
276
|
}));
|
|
260
277
|
},
|
|
261
|
-
|
|
262
|
-
setAndPersist(() => ({
|
|
263
|
-
},
|
|
264
|
-
setDebugMode: (enabled) => {
|
|
265
|
-
setAndPersist(() => ({ debugMode: enabled }));
|
|
266
|
-
},
|
|
267
|
-
isProviderConfigured: (provider) => {
|
|
268
|
-
const state = get();
|
|
269
|
-
return !!state.providers[provider].apiKey;
|
|
270
|
-
},
|
|
271
|
-
getProviderHeader: (provider) => {
|
|
272
|
-
const state = get();
|
|
273
|
-
const key = state.providers[provider].apiKey;
|
|
274
|
-
if (!key) return {};
|
|
275
|
-
const headerMap = {
|
|
276
|
-
[ProviderTypeEnum.REPLICATE]: "X-Replicate-Key",
|
|
277
|
-
[ProviderTypeEnum.FAL]: "X-Fal-Key",
|
|
278
|
-
[ProviderTypeEnum.HUGGINGFACE]: "X-HF-Key",
|
|
279
|
-
[ProviderTypeEnum.GENFEED_AI]: "X-Genfeed-Key"
|
|
280
|
-
};
|
|
281
|
-
return { [headerMap[provider]]: key };
|
|
278
|
+
setShowMinimap: (show) => {
|
|
279
|
+
setAndPersist(() => ({ showMinimap: show }));
|
|
282
280
|
},
|
|
283
|
-
|
|
284
|
-
isSyncing: false,
|
|
281
|
+
showMinimap: initialState.showMinimap,
|
|
285
282
|
syncFromServer: async () => {
|
|
286
283
|
},
|
|
287
284
|
syncToServer: async () => {
|
|
285
|
+
},
|
|
286
|
+
toggleAutoSave: () => {
|
|
287
|
+
setAndPersist((state) => ({ autoSaveEnabled: !state.autoSaveEnabled }));
|
|
288
288
|
}
|
|
289
289
|
};
|
|
290
290
|
});
|
|
291
291
|
var PROVIDER_INFO = {
|
|
292
292
|
[ProviderTypeEnum.REPLICATE]: {
|
|
293
|
-
name: "Replicate",
|
|
294
293
|
description: "Access thousands of open-source AI models",
|
|
295
|
-
docsUrl: "https://replicate.com/docs"
|
|
294
|
+
docsUrl: "https://replicate.com/docs",
|
|
295
|
+
name: "Replicate"
|
|
296
296
|
},
|
|
297
297
|
[ProviderTypeEnum.FAL]: {
|
|
298
|
-
name: "fal.ai",
|
|
299
298
|
description: "Fast inference for image and video generation",
|
|
300
|
-
docsUrl: "https://fal.ai/docs"
|
|
299
|
+
docsUrl: "https://fal.ai/docs",
|
|
300
|
+
name: "fal.ai"
|
|
301
301
|
},
|
|
302
302
|
[ProviderTypeEnum.HUGGINGFACE]: {
|
|
303
|
-
name: "Hugging Face",
|
|
304
303
|
description: "The AI community platform with 500k+ models",
|
|
305
|
-
docsUrl: "https://huggingface.co/docs/api-inference"
|
|
304
|
+
docsUrl: "https://huggingface.co/docs/api-inference",
|
|
305
|
+
name: "Hugging Face"
|
|
306
306
|
},
|
|
307
307
|
[ProviderTypeEnum.GENFEED_AI]: {
|
|
308
|
-
name: "Genfeed AI",
|
|
309
308
|
description: "Built-in models powered by Genfeed",
|
|
310
|
-
docsUrl: "https://genfeed.ai/docs"
|
|
309
|
+
docsUrl: "https://genfeed.ai/docs",
|
|
310
|
+
name: "Genfeed AI"
|
|
311
311
|
}
|
|
312
312
|
};
|
|
313
313
|
|
|
@@ -344,7 +344,9 @@ function extractAllOutputValues(output) {
|
|
|
344
344
|
if (typeof output === "object" && output !== null) {
|
|
345
345
|
const obj = output;
|
|
346
346
|
if ("images" in obj && Array.isArray(obj.images)) {
|
|
347
|
-
return obj.images.filter(
|
|
347
|
+
return obj.images.filter(
|
|
348
|
+
(item) => typeof item === "string"
|
|
349
|
+
);
|
|
348
350
|
}
|
|
349
351
|
if ("image" in obj && typeof obj.image === "string") {
|
|
350
352
|
return [obj.image];
|
|
@@ -371,9 +373,14 @@ function getOutputUpdate(nodeId, output, workflowStore) {
|
|
|
371
373
|
}
|
|
372
374
|
return { outputImage: outputValue };
|
|
373
375
|
}
|
|
374
|
-
if ([
|
|
375
|
-
|
|
376
|
-
|
|
376
|
+
if ([
|
|
377
|
+
"videoGen",
|
|
378
|
+
"animation",
|
|
379
|
+
"videoStitch",
|
|
380
|
+
"lipSync",
|
|
381
|
+
"voiceChange",
|
|
382
|
+
"motionControl"
|
|
383
|
+
].includes(nodeType)) {
|
|
377
384
|
return { outputVideo: outputValue };
|
|
378
385
|
}
|
|
379
386
|
if (nodeType === "textToSpeech") {
|
|
@@ -392,11 +399,11 @@ function getOutputUpdate(nodeId, output, workflowStore) {
|
|
|
392
399
|
// src/stores/execution/helpers/sseSubscription.ts
|
|
393
400
|
var API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://local.genfeed.ai:3001/api";
|
|
394
401
|
var statusMap = {
|
|
402
|
+
complete: NodeStatusEnum.COMPLETE,
|
|
403
|
+
error: NodeStatusEnum.ERROR,
|
|
395
404
|
pending: NodeStatusEnum.IDLE,
|
|
396
405
|
processing: NodeStatusEnum.PROCESSING,
|
|
397
|
-
|
|
398
|
-
succeeded: NodeStatusEnum.COMPLETE,
|
|
399
|
-
error: NodeStatusEnum.ERROR
|
|
406
|
+
succeeded: NodeStatusEnum.COMPLETE
|
|
400
407
|
};
|
|
401
408
|
function applyJobUpdates(jobs, workflowStore, debugMode, set, filterNodeId) {
|
|
402
409
|
if (!jobs || jobs.length === 0) return;
|
|
@@ -413,31 +420,31 @@ function applyJobUpdates(jobs, workflowStore, debugMode, set, filterNodeId) {
|
|
|
413
420
|
if (!existing) {
|
|
414
421
|
didChange = true;
|
|
415
422
|
newJobs.set(job.predictionId, {
|
|
423
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
424
|
+
error,
|
|
416
425
|
nodeId: job.nodeId,
|
|
426
|
+
output,
|
|
417
427
|
predictionId: job.predictionId,
|
|
418
|
-
status,
|
|
419
428
|
progress: 0,
|
|
420
|
-
|
|
421
|
-
error,
|
|
422
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
429
|
+
status
|
|
423
430
|
});
|
|
424
431
|
} else if (existing.status !== status || existing.output !== output || existing.error !== error) {
|
|
425
432
|
didChange = true;
|
|
426
433
|
newJobs.set(job.predictionId, {
|
|
427
434
|
...existing,
|
|
428
|
-
|
|
435
|
+
error,
|
|
429
436
|
output,
|
|
430
|
-
|
|
437
|
+
status
|
|
431
438
|
});
|
|
432
439
|
}
|
|
433
440
|
if (job.result?.debugPayload) {
|
|
434
441
|
const node = workflowStore.getNodeById(job.nodeId);
|
|
435
442
|
newDebugPayloads.push({
|
|
443
|
+
input: job.result.debugPayload.input,
|
|
444
|
+
model: job.result.debugPayload.model,
|
|
436
445
|
nodeId: job.nodeId,
|
|
437
446
|
nodeName: String(node?.data?.label || node?.data?.name || job.nodeId),
|
|
438
447
|
nodeType: node?.type || "unknown",
|
|
439
|
-
model: job.result.debugPayload.model,
|
|
440
|
-
input: job.result.debugPayload.input,
|
|
441
448
|
timestamp: job.result.debugPayload.timestamp
|
|
442
449
|
});
|
|
443
450
|
}
|
|
@@ -447,13 +454,15 @@ function applyJobUpdates(jobs, workflowStore, debugMode, set, filterNodeId) {
|
|
|
447
454
|
useUIStore.getState().setShowDebugPanel(true);
|
|
448
455
|
}
|
|
449
456
|
return {
|
|
450
|
-
jobs: didChange ? newJobs : state.jobs,
|
|
451
457
|
debugPayloads: newDebugPayloads.length > 0 ? [
|
|
452
458
|
...state.debugPayloads.filter(
|
|
453
|
-
(existing) => !newDebugPayloads.some(
|
|
459
|
+
(existing) => !newDebugPayloads.some(
|
|
460
|
+
(newP) => newP.nodeId === existing.nodeId
|
|
461
|
+
)
|
|
454
462
|
),
|
|
455
463
|
...newDebugPayloads
|
|
456
|
-
] : state.debugPayloads
|
|
464
|
+
] : state.debugPayloads,
|
|
465
|
+
jobs: didChange ? newJobs : state.jobs
|
|
457
466
|
};
|
|
458
467
|
});
|
|
459
468
|
}
|
|
@@ -467,8 +476,8 @@ async function reconcileNodeStatuses(executionId) {
|
|
|
467
476
|
const nodeStatus = statusMap[nodeResult.status] ?? NodeStatusEnum.IDLE;
|
|
468
477
|
const isSuccess = nodeResult.status === "complete" || nodeResult.status === "succeeded";
|
|
469
478
|
workflowStore.updateNodeData(nodeResult.nodeId, {
|
|
470
|
-
status: nodeStatus,
|
|
471
479
|
error: isSuccess ? void 0 : nodeResult.error,
|
|
480
|
+
status: nodeStatus,
|
|
472
481
|
...nodeResult.output && getOutputUpdate(nodeResult.nodeId, nodeResult.output, workflowStore)
|
|
473
482
|
});
|
|
474
483
|
if (isSuccess && nodeResult.output) {
|
|
@@ -479,7 +488,9 @@ async function reconcileNodeStatuses(executionId) {
|
|
|
479
488
|
}
|
|
480
489
|
}
|
|
481
490
|
function createExecutionSubscription(executionId, set) {
|
|
482
|
-
const eventSource = new EventSource(
|
|
491
|
+
const eventSource = new EventSource(
|
|
492
|
+
`${API_BASE_URL}/executions/${executionId}/stream`
|
|
493
|
+
);
|
|
483
494
|
const propagatedNodeIds = /* @__PURE__ */ new Set();
|
|
484
495
|
set({ eventSource });
|
|
485
496
|
eventSource.onmessage = (event) => {
|
|
@@ -492,9 +503,13 @@ function createExecutionSubscription(executionId, set) {
|
|
|
492
503
|
const nodeStatus = statusMap[nodeResult.status] ?? NodeStatusEnum.IDLE;
|
|
493
504
|
const isSuccess = nodeResult.status === "complete" || nodeResult.status === "succeeded";
|
|
494
505
|
workflowStore.updateNodeData(nodeResult.nodeId, {
|
|
495
|
-
status: nodeStatus,
|
|
496
506
|
error: isSuccess ? void 0 : nodeResult.error,
|
|
497
|
-
|
|
507
|
+
status: nodeStatus,
|
|
508
|
+
...nodeResult.output && getOutputUpdate(
|
|
509
|
+
nodeResult.nodeId,
|
|
510
|
+
nodeResult.output,
|
|
511
|
+
workflowStore
|
|
512
|
+
)
|
|
498
513
|
});
|
|
499
514
|
if ((nodeResult.status === "complete" || nodeResult.status === "succeeded") && nodeResult.output && !propagatedNodeIds.has(nodeResult.nodeId)) {
|
|
500
515
|
propagatedNodeIds.add(nodeResult.nodeId);
|
|
@@ -505,16 +520,30 @@ function createExecutionSubscription(executionId, set) {
|
|
|
505
520
|
}
|
|
506
521
|
}
|
|
507
522
|
applyJobUpdates(data.jobs, workflowStore, data.debugMode, set);
|
|
508
|
-
const isComplete = [
|
|
509
|
-
|
|
523
|
+
const isComplete = [
|
|
524
|
+
"completed",
|
|
525
|
+
"failed",
|
|
526
|
+
"cancelled",
|
|
527
|
+
"error"
|
|
528
|
+
].includes(data.status);
|
|
529
|
+
const hasFailedNode = (data.nodeResults || []).some(
|
|
530
|
+
(r) => r.status === "error"
|
|
531
|
+
);
|
|
510
532
|
const hasPendingNodes = (data.pendingNodes || []).length > 0;
|
|
511
|
-
const hasProcessingNodes = (data.nodeResults || []).some(
|
|
533
|
+
const hasProcessingNodes = (data.nodeResults || []).some(
|
|
534
|
+
(r) => r.status === "processing"
|
|
535
|
+
);
|
|
512
536
|
const isDone = isComplete || hasFailedNode && !hasPendingNodes && !hasProcessingNodes;
|
|
513
537
|
if (isDone) {
|
|
514
538
|
propagatedNodeIds.clear();
|
|
515
539
|
eventSource.close();
|
|
516
540
|
await reconcileNodeStatuses(executionId);
|
|
517
|
-
set({
|
|
541
|
+
set({
|
|
542
|
+
currentNodeId: null,
|
|
543
|
+
eventSource: null,
|
|
544
|
+
isRunning: false,
|
|
545
|
+
jobs: /* @__PURE__ */ new Map()
|
|
546
|
+
});
|
|
518
547
|
if (data.status === "failed" || hasFailedNode) {
|
|
519
548
|
}
|
|
520
549
|
}
|
|
@@ -525,13 +554,15 @@ function createExecutionSubscription(executionId, set) {
|
|
|
525
554
|
eventSource.onerror = () => {
|
|
526
555
|
eventSource.close();
|
|
527
556
|
void reconcileNodeStatuses(executionId).then(() => {
|
|
528
|
-
set({
|
|
557
|
+
set({ eventSource: null, isRunning: false });
|
|
529
558
|
});
|
|
530
559
|
};
|
|
531
560
|
return eventSource;
|
|
532
561
|
}
|
|
533
562
|
function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
|
|
534
|
-
const eventSource = new EventSource(
|
|
563
|
+
const eventSource = new EventSource(
|
|
564
|
+
`${API_BASE_URL}/executions/${executionId}/stream`
|
|
565
|
+
);
|
|
535
566
|
const propagatedNodeIds = /* @__PURE__ */ new Set();
|
|
536
567
|
eventSource.onmessage = (event) => {
|
|
537
568
|
void (async () => {
|
|
@@ -543,9 +574,13 @@ function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
|
|
|
543
574
|
const nodeStatus = statusMap[nodeResult.status] ?? NodeStatusEnum.IDLE;
|
|
544
575
|
const isSuccess = nodeResult.status === "complete" || nodeResult.status === "succeeded";
|
|
545
576
|
workflowStore.updateNodeData(nodeResult.nodeId, {
|
|
546
|
-
status: nodeStatus,
|
|
547
577
|
error: isSuccess ? void 0 : nodeResult.error,
|
|
548
|
-
|
|
578
|
+
status: nodeStatus,
|
|
579
|
+
...nodeResult.output && getOutputUpdate(
|
|
580
|
+
nodeResult.nodeId,
|
|
581
|
+
nodeResult.output,
|
|
582
|
+
workflowStore
|
|
583
|
+
)
|
|
549
584
|
});
|
|
550
585
|
if ((nodeResult.status === "complete" || nodeResult.status === "succeeded") && nodeResult.output && !propagatedNodeIds.has(nodeResult.nodeId)) {
|
|
551
586
|
propagatedNodeIds.add(nodeResult.nodeId);
|
|
@@ -556,10 +591,19 @@ function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
|
|
|
556
591
|
}
|
|
557
592
|
}
|
|
558
593
|
applyJobUpdates(data.jobs, workflowStore, data.debugMode, set, nodeId);
|
|
559
|
-
const isComplete = [
|
|
560
|
-
|
|
594
|
+
const isComplete = [
|
|
595
|
+
"completed",
|
|
596
|
+
"failed",
|
|
597
|
+
"cancelled",
|
|
598
|
+
"error"
|
|
599
|
+
].includes(data.status);
|
|
600
|
+
const hasFailedNode = (data.nodeResults || []).some(
|
|
601
|
+
(r) => r.status === "error"
|
|
602
|
+
);
|
|
561
603
|
const hasPendingNodes = (data.pendingNodes || []).length > 0;
|
|
562
|
-
const hasProcessingNodes = (data.nodeResults || []).some(
|
|
604
|
+
const hasProcessingNodes = (data.nodeResults || []).some(
|
|
605
|
+
(r) => r.status === "processing"
|
|
606
|
+
);
|
|
563
607
|
const isDone = isComplete || hasFailedNode && !hasPendingNodes && !hasProcessingNodes;
|
|
564
608
|
if (isDone) {
|
|
565
609
|
propagatedNodeIds.clear();
|
|
@@ -568,112 +612,49 @@ function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
|
|
|
568
612
|
set((state) => {
|
|
569
613
|
const newMap = new Map(state.activeNodeExecutions);
|
|
570
614
|
newMap.delete(nodeId);
|
|
571
|
-
return { activeNodeExecutions: newMap };
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
} catch {
|
|
575
|
-
}
|
|
576
|
-
})();
|
|
577
|
-
};
|
|
578
|
-
eventSource.onerror = () => {
|
|
579
|
-
eventSource.close();
|
|
580
|
-
void reconcileNodeStatuses(executionId).then(() => {
|
|
581
|
-
set((state) => {
|
|
582
|
-
const newMap = new Map(state.activeNodeExecutions);
|
|
583
|
-
newMap.delete(nodeId);
|
|
584
|
-
return { activeNodeExecutions: newMap };
|
|
585
|
-
});
|
|
586
|
-
});
|
|
587
|
-
};
|
|
588
|
-
return eventSource;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// src/stores/execution/slices/executionSlice.ts
|
|
592
|
-
var API_BASE_URL2 = process.env.NEXT_PUBLIC_API_URL || "http://local.genfeed.ai:3001/api";
|
|
593
|
-
async function apiPost(path, body) {
|
|
594
|
-
const response = await fetch(`${API_BASE_URL2}${path}`, {
|
|
595
|
-
method: "POST",
|
|
596
|
-
headers: { "Content-Type": "application/json" },
|
|
597
|
-
...body && { body: JSON.stringify(body) }
|
|
598
|
-
});
|
|
599
|
-
if (!response.ok) {
|
|
600
|
-
const errorData = await response.json().catch(() => ({}));
|
|
601
|
-
throw new Error(errorData.message || `API error: ${response.status}`);
|
|
602
|
-
}
|
|
603
|
-
return response.json();
|
|
604
|
-
}
|
|
605
|
-
var createExecutionSlice = (set, get) => ({
|
|
606
|
-
executeWorkflow: async () => {
|
|
607
|
-
const { isRunning, resetExecution } = get();
|
|
608
|
-
if (isRunning) return;
|
|
609
|
-
const workflowStore = useWorkflowStore.getState();
|
|
610
|
-
const debugMode = useSettingsStore.getState().debugMode;
|
|
611
|
-
const validation = workflowStore.validateWorkflow();
|
|
612
|
-
if (!validation.isValid) {
|
|
613
|
-
set({ validationErrors: validation });
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
set({ validationErrors: null });
|
|
617
|
-
resetExecution();
|
|
618
|
-
if (debugMode) {
|
|
619
|
-
useUIStore.getState().setShowDebugPanel(true);
|
|
620
|
-
}
|
|
621
|
-
if (workflowStore.isDirty || !workflowStore.workflowId) {
|
|
622
|
-
try {
|
|
623
|
-
await workflowStore.saveWorkflow();
|
|
624
|
-
} catch {
|
|
625
|
-
set({
|
|
626
|
-
validationErrors: {
|
|
627
|
-
isValid: false,
|
|
628
|
-
errors: [{ nodeId: "", message: "Failed to save workflow", severity: "error" }],
|
|
629
|
-
warnings: []
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
const workflowId = workflowStore.workflowId;
|
|
636
|
-
if (!workflowId) {
|
|
637
|
-
set({
|
|
638
|
-
validationErrors: {
|
|
639
|
-
isValid: false,
|
|
640
|
-
errors: [{ nodeId: "", message: "Workflow must be saved first", severity: "error" }],
|
|
641
|
-
warnings: []
|
|
642
|
-
}
|
|
643
|
-
});
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
set({ isRunning: true });
|
|
647
|
-
for (const node of workflowStore.nodes) {
|
|
648
|
-
workflowStore.updateNodeData(node.id, {
|
|
649
|
-
status: NodeStatusEnum.IDLE,
|
|
650
|
-
error: void 0,
|
|
651
|
-
progress: void 0
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
try {
|
|
655
|
-
const execution = await apiPost(`/workflows/${workflowId}/execute`, {
|
|
656
|
-
debugMode
|
|
657
|
-
});
|
|
658
|
-
const executionId = execution._id;
|
|
659
|
-
set({ executionId });
|
|
660
|
-
createExecutionSubscription(executionId, set);
|
|
661
|
-
} catch (error) {
|
|
662
|
-
set({
|
|
663
|
-
isRunning: false,
|
|
664
|
-
validationErrors: {
|
|
665
|
-
isValid: false,
|
|
666
|
-
errors: [
|
|
667
|
-
{
|
|
668
|
-
nodeId: "",
|
|
669
|
-
message: error instanceof Error ? error.message : "Execution failed",
|
|
670
|
-
severity: "error"
|
|
671
|
-
}
|
|
672
|
-
],
|
|
673
|
-
warnings: []
|
|
615
|
+
return { activeNodeExecutions: newMap };
|
|
616
|
+
});
|
|
674
617
|
}
|
|
618
|
+
} catch {
|
|
619
|
+
}
|
|
620
|
+
})();
|
|
621
|
+
};
|
|
622
|
+
eventSource.onerror = () => {
|
|
623
|
+
eventSource.close();
|
|
624
|
+
void reconcileNodeStatuses(executionId).then(() => {
|
|
625
|
+
set((state) => {
|
|
626
|
+
const newMap = new Map(state.activeNodeExecutions);
|
|
627
|
+
newMap.delete(nodeId);
|
|
628
|
+
return { activeNodeExecutions: newMap };
|
|
675
629
|
});
|
|
676
|
-
}
|
|
630
|
+
});
|
|
631
|
+
};
|
|
632
|
+
return eventSource;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/stores/execution/slices/executionSlice.ts
|
|
636
|
+
var API_BASE_URL2 = process.env.NEXT_PUBLIC_API_URL || "http://local.genfeed.ai:3001/api";
|
|
637
|
+
async function apiPost(path, body) {
|
|
638
|
+
const response = await fetch(`${API_BASE_URL2}${path}`, {
|
|
639
|
+
headers: { "Content-Type": "application/json" },
|
|
640
|
+
method: "POST",
|
|
641
|
+
...body && { body: JSON.stringify(body) }
|
|
642
|
+
});
|
|
643
|
+
if (!response.ok) {
|
|
644
|
+
const errorData = await response.json().catch(() => ({}));
|
|
645
|
+
throw new Error(
|
|
646
|
+
errorData.message || `API error: ${response.status}`
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
return response.json();
|
|
650
|
+
}
|
|
651
|
+
var createExecutionSlice = (set, get) => ({
|
|
652
|
+
canResumeFromFailed: () => {
|
|
653
|
+
const { executionId, lastFailedNodeId, isRunning } = get();
|
|
654
|
+
return !isRunning && Boolean(executionId) && Boolean(lastFailedNodeId);
|
|
655
|
+
},
|
|
656
|
+
clearValidationErrors: () => {
|
|
657
|
+
set({ validationErrors: null });
|
|
677
658
|
},
|
|
678
659
|
executeNode: async (nodeId) => {
|
|
679
660
|
const workflowStore = useWorkflowStore.getState();
|
|
@@ -683,8 +664,8 @@ var createExecutionSlice = (set, get) => ({
|
|
|
683
664
|
await workflowStore.saveWorkflow();
|
|
684
665
|
} catch {
|
|
685
666
|
workflowStore.updateNodeData(nodeId, {
|
|
686
|
-
|
|
687
|
-
|
|
667
|
+
error: "Failed to save workflow",
|
|
668
|
+
status: NodeStatusEnum.ERROR
|
|
688
669
|
});
|
|
689
670
|
return;
|
|
690
671
|
}
|
|
@@ -692,8 +673,8 @@ var createExecutionSlice = (set, get) => ({
|
|
|
692
673
|
const workflowId = workflowStore.workflowId;
|
|
693
674
|
if (!workflowId) {
|
|
694
675
|
workflowStore.updateNodeData(nodeId, {
|
|
695
|
-
|
|
696
|
-
|
|
676
|
+
error: "Workflow must be saved first",
|
|
677
|
+
status: NodeStatusEnum.ERROR
|
|
697
678
|
});
|
|
698
679
|
return;
|
|
699
680
|
}
|
|
@@ -701,16 +682,24 @@ var createExecutionSlice = (set, get) => ({
|
|
|
701
682
|
useUIStore.getState().setShowDebugPanel(true);
|
|
702
683
|
}
|
|
703
684
|
try {
|
|
704
|
-
const execution = await apiPost(
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
685
|
+
const execution = await apiPost(
|
|
686
|
+
`/workflows/${workflowId}/execute`,
|
|
687
|
+
{
|
|
688
|
+
debugMode,
|
|
689
|
+
selectedNodeIds: [nodeId]
|
|
690
|
+
}
|
|
691
|
+
);
|
|
708
692
|
const executionId = execution._id;
|
|
709
|
-
const eventSource = createNodeExecutionSubscription(
|
|
693
|
+
const eventSource = createNodeExecutionSubscription(
|
|
694
|
+
executionId,
|
|
695
|
+
nodeId,
|
|
696
|
+
set,
|
|
697
|
+
get
|
|
698
|
+
);
|
|
710
699
|
const nodeExecution = {
|
|
700
|
+
eventSource,
|
|
711
701
|
executionId,
|
|
712
|
-
nodeIds: [nodeId]
|
|
713
|
-
eventSource
|
|
702
|
+
nodeIds: [nodeId]
|
|
714
703
|
};
|
|
715
704
|
set((state) => {
|
|
716
705
|
const newMap = new Map(state.activeNodeExecutions);
|
|
@@ -719,8 +708,8 @@ var createExecutionSlice = (set, get) => ({
|
|
|
719
708
|
});
|
|
720
709
|
} catch (error) {
|
|
721
710
|
workflowStore.updateNodeData(nodeId, {
|
|
722
|
-
|
|
723
|
-
|
|
711
|
+
error: error instanceof Error ? error.message : "Node execution failed",
|
|
712
|
+
status: NodeStatusEnum.ERROR
|
|
724
713
|
});
|
|
725
714
|
}
|
|
726
715
|
},
|
|
@@ -733,8 +722,10 @@ var createExecutionSlice = (set, get) => ({
|
|
|
733
722
|
if (selectedNodeIds.length === 0) {
|
|
734
723
|
set({
|
|
735
724
|
validationErrors: {
|
|
725
|
+
errors: [
|
|
726
|
+
{ message: "No nodes selected", nodeId: "", severity: "error" }
|
|
727
|
+
],
|
|
736
728
|
isValid: false,
|
|
737
|
-
errors: [{ nodeId: "", message: "No nodes selected", severity: "error" }],
|
|
738
729
|
warnings: []
|
|
739
730
|
}
|
|
740
731
|
});
|
|
@@ -748,8 +739,14 @@ var createExecutionSlice = (set, get) => ({
|
|
|
748
739
|
} catch {
|
|
749
740
|
set({
|
|
750
741
|
validationErrors: {
|
|
742
|
+
errors: [
|
|
743
|
+
{
|
|
744
|
+
message: "Failed to save workflow",
|
|
745
|
+
nodeId: "",
|
|
746
|
+
severity: "error"
|
|
747
|
+
}
|
|
748
|
+
],
|
|
751
749
|
isValid: false,
|
|
752
|
-
errors: [{ nodeId: "", message: "Failed to save workflow", severity: "error" }],
|
|
753
750
|
warnings: []
|
|
754
751
|
}
|
|
755
752
|
});
|
|
@@ -760,29 +757,38 @@ var createExecutionSlice = (set, get) => ({
|
|
|
760
757
|
if (!workflowId) {
|
|
761
758
|
set({
|
|
762
759
|
validationErrors: {
|
|
760
|
+
errors: [
|
|
761
|
+
{
|
|
762
|
+
message: "Workflow must be saved first",
|
|
763
|
+
nodeId: "",
|
|
764
|
+
severity: "error"
|
|
765
|
+
}
|
|
766
|
+
],
|
|
763
767
|
isValid: false,
|
|
764
|
-
errors: [{ nodeId: "", message: "Workflow must be saved first", severity: "error" }],
|
|
765
768
|
warnings: []
|
|
766
769
|
}
|
|
767
770
|
});
|
|
768
771
|
return;
|
|
769
772
|
}
|
|
770
|
-
set({
|
|
773
|
+
set({ executingNodeIds: selectedNodeIds, isRunning: true });
|
|
771
774
|
if (debugMode) {
|
|
772
775
|
useUIStore.getState().setShowDebugPanel(true);
|
|
773
776
|
}
|
|
774
777
|
for (const nodeId of selectedNodeIds) {
|
|
775
778
|
workflowStore.updateNodeData(nodeId, {
|
|
776
|
-
status: NodeStatusEnum.IDLE,
|
|
777
779
|
error: void 0,
|
|
778
|
-
progress: void 0
|
|
780
|
+
progress: void 0,
|
|
781
|
+
status: NodeStatusEnum.IDLE
|
|
779
782
|
});
|
|
780
783
|
}
|
|
781
784
|
try {
|
|
782
|
-
const execution = await apiPost(
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
785
|
+
const execution = await apiPost(
|
|
786
|
+
`/workflows/${workflowId}/execute`,
|
|
787
|
+
{
|
|
788
|
+
debugMode,
|
|
789
|
+
selectedNodeIds
|
|
790
|
+
}
|
|
791
|
+
);
|
|
786
792
|
const executionId = execution._id;
|
|
787
793
|
set({ executionId });
|
|
788
794
|
createExecutionSubscription(executionId, set);
|
|
@@ -790,19 +796,139 @@ var createExecutionSlice = (set, get) => ({
|
|
|
790
796
|
set({
|
|
791
797
|
isRunning: false,
|
|
792
798
|
validationErrors: {
|
|
799
|
+
errors: [
|
|
800
|
+
{
|
|
801
|
+
message: error instanceof Error ? error.message : "Partial execution failed",
|
|
802
|
+
nodeId: "",
|
|
803
|
+
severity: "error"
|
|
804
|
+
}
|
|
805
|
+
],
|
|
806
|
+
isValid: false,
|
|
807
|
+
warnings: []
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
executeWorkflow: async () => {
|
|
813
|
+
const { isRunning, resetExecution } = get();
|
|
814
|
+
if (isRunning) return;
|
|
815
|
+
const workflowStore = useWorkflowStore.getState();
|
|
816
|
+
const debugMode = useSettingsStore.getState().debugMode;
|
|
817
|
+
const validation = workflowStore.validateWorkflow();
|
|
818
|
+
if (!validation.isValid) {
|
|
819
|
+
set({ validationErrors: validation });
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
set({ validationErrors: null });
|
|
823
|
+
resetExecution();
|
|
824
|
+
if (debugMode) {
|
|
825
|
+
useUIStore.getState().setShowDebugPanel(true);
|
|
826
|
+
}
|
|
827
|
+
if (workflowStore.isDirty || !workflowStore.workflowId) {
|
|
828
|
+
try {
|
|
829
|
+
await workflowStore.saveWorkflow();
|
|
830
|
+
} catch {
|
|
831
|
+
set({
|
|
832
|
+
validationErrors: {
|
|
833
|
+
errors: [
|
|
834
|
+
{
|
|
835
|
+
message: "Failed to save workflow",
|
|
836
|
+
nodeId: "",
|
|
837
|
+
severity: "error"
|
|
838
|
+
}
|
|
839
|
+
],
|
|
840
|
+
isValid: false,
|
|
841
|
+
warnings: []
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
const workflowId = workflowStore.workflowId;
|
|
848
|
+
if (!workflowId) {
|
|
849
|
+
set({
|
|
850
|
+
validationErrors: {
|
|
851
|
+
errors: [
|
|
852
|
+
{
|
|
853
|
+
message: "Workflow must be saved first",
|
|
854
|
+
nodeId: "",
|
|
855
|
+
severity: "error"
|
|
856
|
+
}
|
|
857
|
+
],
|
|
793
858
|
isValid: false,
|
|
859
|
+
warnings: []
|
|
860
|
+
}
|
|
861
|
+
});
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
set({ isRunning: true });
|
|
865
|
+
for (const node of workflowStore.nodes) {
|
|
866
|
+
workflowStore.updateNodeData(node.id, {
|
|
867
|
+
error: void 0,
|
|
868
|
+
progress: void 0,
|
|
869
|
+
status: NodeStatusEnum.IDLE
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
try {
|
|
873
|
+
const execution = await apiPost(
|
|
874
|
+
`/workflows/${workflowId}/execute`,
|
|
875
|
+
{
|
|
876
|
+
debugMode
|
|
877
|
+
}
|
|
878
|
+
);
|
|
879
|
+
const executionId = execution._id;
|
|
880
|
+
set({ executionId });
|
|
881
|
+
createExecutionSubscription(executionId, set);
|
|
882
|
+
} catch (error) {
|
|
883
|
+
set({
|
|
884
|
+
isRunning: false,
|
|
885
|
+
validationErrors: {
|
|
794
886
|
errors: [
|
|
795
887
|
{
|
|
888
|
+
message: error instanceof Error ? error.message : "Execution failed",
|
|
796
889
|
nodeId: "",
|
|
797
|
-
message: error instanceof Error ? error.message : "Partial execution failed",
|
|
798
890
|
severity: "error"
|
|
799
891
|
}
|
|
800
892
|
],
|
|
893
|
+
isValid: false,
|
|
801
894
|
warnings: []
|
|
802
895
|
}
|
|
803
896
|
});
|
|
804
897
|
}
|
|
805
898
|
},
|
|
899
|
+
isNodeExecuting: (nodeId) => {
|
|
900
|
+
const { activeNodeExecutions } = get();
|
|
901
|
+
return activeNodeExecutions.has(nodeId);
|
|
902
|
+
},
|
|
903
|
+
resetExecution: () => {
|
|
904
|
+
const { eventSource, activeNodeExecutions } = get();
|
|
905
|
+
if (eventSource) {
|
|
906
|
+
eventSource.close();
|
|
907
|
+
}
|
|
908
|
+
for (const nodeExecution of activeNodeExecutions.values()) {
|
|
909
|
+
nodeExecution.eventSource.close();
|
|
910
|
+
}
|
|
911
|
+
set({
|
|
912
|
+
activeNodeExecutions: /* @__PURE__ */ new Map(),
|
|
913
|
+
actualCost: 0,
|
|
914
|
+
currentNodeId: null,
|
|
915
|
+
debugPayloads: [],
|
|
916
|
+
eventSource: null,
|
|
917
|
+
executingNodeIds: [],
|
|
918
|
+
executionId: null,
|
|
919
|
+
isRunning: false,
|
|
920
|
+
jobs: /* @__PURE__ */ new Map(),
|
|
921
|
+
lastFailedNodeId: null
|
|
922
|
+
});
|
|
923
|
+
const workflowStore = useWorkflowStore.getState();
|
|
924
|
+
for (const node of workflowStore.nodes) {
|
|
925
|
+
workflowStore.updateNodeData(node.id, {
|
|
926
|
+
error: void 0,
|
|
927
|
+
progress: void 0,
|
|
928
|
+
status: NodeStatusEnum.IDLE
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
},
|
|
806
932
|
resumeFromFailed: async () => {
|
|
807
933
|
const { isRunning, executionId, lastFailedNodeId } = get();
|
|
808
934
|
if (isRunning || !executionId || !lastFailedNodeId) return;
|
|
@@ -812,8 +938,14 @@ var createExecutionSlice = (set, get) => ({
|
|
|
812
938
|
if (!workflowId) {
|
|
813
939
|
set({
|
|
814
940
|
validationErrors: {
|
|
941
|
+
errors: [
|
|
942
|
+
{
|
|
943
|
+
message: "Workflow must be saved first",
|
|
944
|
+
nodeId: "",
|
|
945
|
+
severity: "error"
|
|
946
|
+
}
|
|
947
|
+
],
|
|
815
948
|
isValid: false,
|
|
816
|
-
errors: [{ nodeId: "", message: "Workflow must be saved first", severity: "error" }],
|
|
817
949
|
warnings: []
|
|
818
950
|
}
|
|
819
951
|
});
|
|
@@ -824,14 +956,17 @@ var createExecutionSlice = (set, get) => ({
|
|
|
824
956
|
useUIStore.getState().setShowDebugPanel(true);
|
|
825
957
|
}
|
|
826
958
|
workflowStore.updateNodeData(lastFailedNodeId, {
|
|
827
|
-
status: NodeStatusEnum.IDLE,
|
|
828
959
|
error: void 0,
|
|
829
|
-
progress: void 0
|
|
960
|
+
progress: void 0,
|
|
961
|
+
status: NodeStatusEnum.IDLE
|
|
830
962
|
});
|
|
831
963
|
try {
|
|
832
|
-
const execution = await apiPost(
|
|
833
|
-
|
|
834
|
-
|
|
964
|
+
const execution = await apiPost(
|
|
965
|
+
`/workflows/${workflowId}/execute`,
|
|
966
|
+
{
|
|
967
|
+
debugMode
|
|
968
|
+
}
|
|
969
|
+
);
|
|
835
970
|
const newExecutionId = execution._id;
|
|
836
971
|
set({ executionId: newExecutionId, lastFailedNodeId: null });
|
|
837
972
|
createExecutionSubscription(newExecutionId, set);
|
|
@@ -839,19 +974,22 @@ var createExecutionSlice = (set, get) => ({
|
|
|
839
974
|
set({
|
|
840
975
|
isRunning: false,
|
|
841
976
|
validationErrors: {
|
|
842
|
-
isValid: false,
|
|
843
977
|
errors: [
|
|
844
978
|
{
|
|
845
|
-
nodeId: "",
|
|
846
979
|
message: error instanceof Error ? error.message : "Resume failed",
|
|
980
|
+
nodeId: "",
|
|
847
981
|
severity: "error"
|
|
848
982
|
}
|
|
849
983
|
],
|
|
984
|
+
isValid: false,
|
|
850
985
|
warnings: []
|
|
851
986
|
}
|
|
852
987
|
});
|
|
853
988
|
}
|
|
854
989
|
},
|
|
990
|
+
setEstimatedCost: (cost) => {
|
|
991
|
+
set({ estimatedCost: cost });
|
|
992
|
+
},
|
|
855
993
|
stopExecution: () => {
|
|
856
994
|
const { eventSource, executionId } = get();
|
|
857
995
|
if (eventSource) {
|
|
@@ -862,9 +1000,9 @@ var createExecutionSlice = (set, get) => ({
|
|
|
862
1000
|
});
|
|
863
1001
|
}
|
|
864
1002
|
set({
|
|
865
|
-
|
|
1003
|
+
currentNodeId: null,
|
|
866
1004
|
eventSource: null,
|
|
867
|
-
|
|
1005
|
+
isRunning: false
|
|
868
1006
|
});
|
|
869
1007
|
},
|
|
870
1008
|
stopNodeExecution: (nodeId) => {
|
|
@@ -881,50 +1019,10 @@ var createExecutionSlice = (set, get) => ({
|
|
|
881
1019
|
});
|
|
882
1020
|
}
|
|
883
1021
|
const workflowStore = useWorkflowStore.getState();
|
|
884
|
-
workflowStore.updateNodeData(nodeId, {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const { activeNodeExecutions } = get();
|
|
888
|
-
return activeNodeExecutions.has(nodeId);
|
|
889
|
-
},
|
|
890
|
-
clearValidationErrors: () => {
|
|
891
|
-
set({ validationErrors: null });
|
|
892
|
-
},
|
|
893
|
-
resetExecution: () => {
|
|
894
|
-
const { eventSource, activeNodeExecutions } = get();
|
|
895
|
-
if (eventSource) {
|
|
896
|
-
eventSource.close();
|
|
897
|
-
}
|
|
898
|
-
for (const nodeExecution of activeNodeExecutions.values()) {
|
|
899
|
-
nodeExecution.eventSource.close();
|
|
900
|
-
}
|
|
901
|
-
set({
|
|
902
|
-
isRunning: false,
|
|
903
|
-
jobs: /* @__PURE__ */ new Map(),
|
|
904
|
-
executionId: null,
|
|
905
|
-
currentNodeId: null,
|
|
906
|
-
executingNodeIds: [],
|
|
907
|
-
eventSource: null,
|
|
908
|
-
actualCost: 0,
|
|
909
|
-
lastFailedNodeId: null,
|
|
910
|
-
debugPayloads: [],
|
|
911
|
-
activeNodeExecutions: /* @__PURE__ */ new Map()
|
|
1022
|
+
workflowStore.updateNodeData(nodeId, {
|
|
1023
|
+
error: void 0,
|
|
1024
|
+
status: NodeStatusEnum.IDLE
|
|
912
1025
|
});
|
|
913
|
-
const workflowStore = useWorkflowStore.getState();
|
|
914
|
-
for (const node of workflowStore.nodes) {
|
|
915
|
-
workflowStore.updateNodeData(node.id, {
|
|
916
|
-
status: NodeStatusEnum.IDLE,
|
|
917
|
-
error: void 0,
|
|
918
|
-
progress: void 0
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
},
|
|
922
|
-
canResumeFromFailed: () => {
|
|
923
|
-
const { executionId, lastFailedNodeId, isRunning } = get();
|
|
924
|
-
return !isRunning && Boolean(executionId) && Boolean(lastFailedNodeId);
|
|
925
|
-
},
|
|
926
|
-
setEstimatedCost: (cost) => {
|
|
927
|
-
set({ estimatedCost: cost });
|
|
928
1026
|
}
|
|
929
1027
|
});
|
|
930
1028
|
|
|
@@ -934,17 +1032,24 @@ var createJobSlice = (set, get) => ({
|
|
|
934
1032
|
set((state) => {
|
|
935
1033
|
const newJobs = new Map(state.jobs);
|
|
936
1034
|
newJobs.set(predictionId, {
|
|
1035
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1036
|
+
error: null,
|
|
937
1037
|
nodeId,
|
|
1038
|
+
output: null,
|
|
938
1039
|
predictionId,
|
|
939
|
-
status: "pending",
|
|
940
1040
|
progress: 0,
|
|
941
|
-
|
|
942
|
-
error: null,
|
|
943
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1041
|
+
status: "pending"
|
|
944
1042
|
});
|
|
945
1043
|
return { jobs: newJobs };
|
|
946
1044
|
});
|
|
947
1045
|
},
|
|
1046
|
+
getJobByNodeId: (nodeId) => {
|
|
1047
|
+
const { jobs } = get();
|
|
1048
|
+
for (const job of jobs.values()) {
|
|
1049
|
+
if (job.nodeId === nodeId) return job;
|
|
1050
|
+
}
|
|
1051
|
+
return void 0;
|
|
1052
|
+
},
|
|
948
1053
|
updateJob: (predictionId, updates) => {
|
|
949
1054
|
set((state) => {
|
|
950
1055
|
const newJobs = new Map(state.jobs);
|
|
@@ -954,13 +1059,6 @@ var createJobSlice = (set, get) => ({
|
|
|
954
1059
|
}
|
|
955
1060
|
return { jobs: newJobs };
|
|
956
1061
|
});
|
|
957
|
-
},
|
|
958
|
-
getJobByNodeId: (nodeId) => {
|
|
959
|
-
const { jobs } = get();
|
|
960
|
-
for (const job of jobs.values()) {
|
|
961
|
-
if (job.nodeId === nodeId) return job;
|
|
962
|
-
}
|
|
963
|
-
return void 0;
|
|
964
1062
|
}
|
|
965
1063
|
});
|
|
966
1064
|
|
|
@@ -968,20 +1066,8 @@ var createJobSlice = (set, get) => ({
|
|
|
968
1066
|
var useExecutionStore = create()((...args) => {
|
|
969
1067
|
const [set] = args;
|
|
970
1068
|
return {
|
|
971
|
-
// Initial state
|
|
972
|
-
isRunning: false,
|
|
973
|
-
executionId: null,
|
|
974
|
-
currentNodeId: null,
|
|
975
|
-
executingNodeIds: [],
|
|
976
|
-
validationErrors: null,
|
|
977
|
-
eventSource: null,
|
|
978
|
-
lastFailedNodeId: null,
|
|
979
|
-
pausedAtNodeId: null,
|
|
980
|
-
jobs: /* @__PURE__ */ new Map(),
|
|
981
|
-
estimatedCost: 0,
|
|
982
|
-
actualCost: 0,
|
|
983
|
-
debugPayloads: [],
|
|
984
1069
|
activeNodeExecutions: /* @__PURE__ */ new Map(),
|
|
1070
|
+
actualCost: 0,
|
|
985
1071
|
// Debug payload actions
|
|
986
1072
|
addDebugPayload: (payload) => {
|
|
987
1073
|
set((state) => ({
|
|
@@ -991,6 +1077,18 @@ var useExecutionStore = create()((...args) => {
|
|
|
991
1077
|
clearDebugPayloads: () => {
|
|
992
1078
|
set({ debugPayloads: [] });
|
|
993
1079
|
},
|
|
1080
|
+
currentNodeId: null,
|
|
1081
|
+
debugPayloads: [],
|
|
1082
|
+
estimatedCost: 0,
|
|
1083
|
+
eventSource: null,
|
|
1084
|
+
executingNodeIds: [],
|
|
1085
|
+
executionId: null,
|
|
1086
|
+
// Initial state
|
|
1087
|
+
isRunning: false,
|
|
1088
|
+
jobs: /* @__PURE__ */ new Map(),
|
|
1089
|
+
lastFailedNodeId: null,
|
|
1090
|
+
pausedAtNodeId: null,
|
|
1091
|
+
validationErrors: null,
|
|
994
1092
|
// Compose slices
|
|
995
1093
|
...createJobSlice(...args),
|
|
996
1094
|
...createExecutionSlice(...args)
|