@mesantosrai/pipeline-canvas 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +545 -0
  3. package/dist/_virtual/dynamic-import-helper.mjs +17 -0
  4. package/dist/_virtual/dynamic-import-helper.mjs.map +1 -0
  5. package/dist/components/CustomHandle.d.ts +9 -0
  6. package/dist/components/CustomHandle.d.ts.map +1 -0
  7. package/dist/components/CustomHandle.mjs +18 -0
  8. package/dist/components/CustomHandle.mjs.map +1 -0
  9. package/dist/components/ExecutionLogsPanel.d.ts +3 -0
  10. package/dist/components/ExecutionLogsPanel.d.ts.map +1 -0
  11. package/dist/components/ExecutionLogsPanel.mjs +189 -0
  12. package/dist/components/ExecutionLogsPanel.mjs.map +1 -0
  13. package/dist/components/NodeContextMenu.d.ts +15 -0
  14. package/dist/components/NodeContextMenu.d.ts.map +1 -0
  15. package/dist/components/NodeContextMenu.mjs +110 -0
  16. package/dist/components/NodeContextMenu.mjs.map +1 -0
  17. package/dist/components/PipelineCanvas.d.ts +4 -0
  18. package/dist/components/PipelineCanvas.d.ts.map +1 -0
  19. package/dist/components/PipelineCanvas.mjs +1016 -0
  20. package/dist/components/PipelineCanvas.mjs.map +1 -0
  21. package/dist/components/PipelineCanvasProvider.d.ts +30 -0
  22. package/dist/components/PipelineCanvasProvider.d.ts.map +1 -0
  23. package/dist/components/PipelineCanvasProvider.mjs +7 -0
  24. package/dist/components/PipelineCanvasProvider.mjs.map +1 -0
  25. package/dist/components/PipelineExecution.d.ts +16 -0
  26. package/dist/components/PipelineExecution.d.ts.map +1 -0
  27. package/dist/components/PipelineExecution.mjs +310 -0
  28. package/dist/components/PipelineExecution.mjs.map +1 -0
  29. package/dist/components/PipelineManager.d.ts +8 -0
  30. package/dist/components/PipelineManager.d.ts.map +1 -0
  31. package/dist/components/PipelineManager.mjs +143 -0
  32. package/dist/components/PipelineManager.mjs.map +1 -0
  33. package/dist/components/PipelineNodeConfig.d.ts +11 -0
  34. package/dist/components/PipelineNodeConfig.d.ts.map +1 -0
  35. package/dist/components/PipelineNodeConfig.mjs +1808 -0
  36. package/dist/components/PipelineNodeConfig.mjs.map +1 -0
  37. package/dist/components/PipelineNodePalette.d.ts +3 -0
  38. package/dist/components/PipelineNodePalette.d.ts.map +1 -0
  39. package/dist/components/PipelineNodePalette.mjs +87 -0
  40. package/dist/components/PipelineNodePalette.mjs.map +1 -0
  41. package/dist/components/SavePipelineDialog.d.ts +9 -0
  42. package/dist/components/SavePipelineDialog.d.ts.map +1 -0
  43. package/dist/components/SavePipelineDialog.mjs +140 -0
  44. package/dist/components/SavePipelineDialog.mjs.map +1 -0
  45. package/dist/components/SavedPipelinesList.d.ts +3 -0
  46. package/dist/components/SavedPipelinesList.d.ts.map +1 -0
  47. package/dist/components/SavedPipelinesList.mjs +172 -0
  48. package/dist/components/SavedPipelinesList.mjs.map +1 -0
  49. package/dist/components/index.d.ts +8 -0
  50. package/dist/components/index.d.ts.map +1 -0
  51. package/dist/components/ui/alert.d.ts +9 -0
  52. package/dist/components/ui/alert.d.ts.map +1 -0
  53. package/dist/components/ui/alert.mjs +51 -0
  54. package/dist/components/ui/alert.mjs.map +1 -0
  55. package/dist/components/ui/button.d.ts +12 -0
  56. package/dist/components/ui/button.d.ts.map +1 -0
  57. package/dist/components/ui/button.mjs +45 -0
  58. package/dist/components/ui/button.mjs.map +1 -0
  59. package/dist/components/ui/dialog.d.ts +20 -0
  60. package/dist/components/ui/dialog.d.ts.map +1 -0
  61. package/dist/components/ui/dialog.mjs +99 -0
  62. package/dist/components/ui/dialog.mjs.map +1 -0
  63. package/dist/components/ui/index.d.ts +8 -0
  64. package/dist/components/ui/index.d.ts.map +1 -0
  65. package/dist/components/ui/input.d.ts +6 -0
  66. package/dist/components/ui/input.d.ts.map +1 -0
  67. package/dist/components/ui/input.mjs +22 -0
  68. package/dist/components/ui/input.mjs.map +1 -0
  69. package/dist/components/ui/label.d.ts +6 -0
  70. package/dist/components/ui/label.d.ts.map +1 -0
  71. package/dist/components/ui/label.mjs +20 -0
  72. package/dist/components/ui/label.mjs.map +1 -0
  73. package/dist/components/ui/select.d.ts +14 -0
  74. package/dist/components/ui/select.d.ts.map +1 -0
  75. package/dist/components/ui/select.mjs +121 -0
  76. package/dist/components/ui/select.mjs.map +1 -0
  77. package/dist/components/ui/tooltip.d.ts +8 -0
  78. package/dist/components/ui/tooltip.d.ts.map +1 -0
  79. package/dist/components/ui/tooltip.mjs +24 -0
  80. package/dist/components/ui/tooltip.mjs.map +1 -0
  81. package/dist/context/PipelineContext.d.ts +50 -0
  82. package/dist/context/PipelineContext.d.ts.map +1 -0
  83. package/dist/context/PipelineContext.mjs +36 -0
  84. package/dist/context/PipelineContext.mjs.map +1 -0
  85. package/dist/index.d.ts +12 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.mjs +45 -0
  88. package/dist/index.mjs.map +1 -0
  89. package/dist/lib/utils.d.ts +3 -0
  90. package/dist/lib/utils.d.ts.map +1 -0
  91. package/dist/lib/utils.mjs +9 -0
  92. package/dist/lib/utils.mjs.map +1 -0
  93. package/dist/node_modules/zustand/esm/middleware.mjs +256 -0
  94. package/dist/node_modules/zustand/esm/middleware.mjs.map +1 -0
  95. package/dist/nodes/alphafold_node/node.json.mjs +82 -0
  96. package/dist/nodes/alphafold_node/node.json.mjs.map +1 -0
  97. package/dist/nodes/http_request_node/node.json.mjs +383 -0
  98. package/dist/nodes/http_request_node/node.json.mjs.map +1 -0
  99. package/dist/nodes/input_node/node.json.mjs +51 -0
  100. package/dist/nodes/input_node/node.json.mjs.map +1 -0
  101. package/dist/nodes/message_input_node/node.json.mjs +90 -0
  102. package/dist/nodes/message_input_node/node.json.mjs.map +1 -0
  103. package/dist/nodes/proteinmpnn_node/node.json.mjs +83 -0
  104. package/dist/nodes/proteinmpnn_node/node.json.mjs.map +1 -0
  105. package/dist/nodes/rfdiffusion_node/node.json.mjs +281 -0
  106. package/dist/nodes/rfdiffusion_node/node.json.mjs.map +1 -0
  107. package/dist/store/pipelineStore.d.ts +108 -0
  108. package/dist/store/pipelineStore.d.ts.map +1 -0
  109. package/dist/store/pipelineStore.mjs +633 -0
  110. package/dist/store/pipelineStore.mjs.map +1 -0
  111. package/dist/style.css +1 -0
  112. package/dist/types/dependencies.d.ts +93 -0
  113. package/dist/types/dependencies.d.ts.map +1 -0
  114. package/dist/types/index.d.ts +56 -0
  115. package/dist/types/index.d.ts.map +1 -0
  116. package/dist/types/logger.d.ts +67 -0
  117. package/dist/types/logger.d.ts.map +1 -0
  118. package/dist/types/logger.mjs +22 -0
  119. package/dist/types/logger.mjs.map +1 -0
  120. package/dist/utils/executionEngine.d.ts +27 -0
  121. package/dist/utils/executionEngine.d.ts.map +1 -0
  122. package/dist/utils/executionEngine.mjs +461 -0
  123. package/dist/utils/executionEngine.mjs.map +1 -0
  124. package/dist/utils/index.d.ts +6 -0
  125. package/dist/utils/index.d.ts.map +1 -0
  126. package/dist/utils/logger.d.ts +23 -0
  127. package/dist/utils/logger.d.ts.map +1 -0
  128. package/dist/utils/logger.mjs +29 -0
  129. package/dist/utils/logger.mjs.map +1 -0
  130. package/dist/utils/nodeLoader.d.ts +76 -0
  131. package/dist/utils/nodeLoader.d.ts.map +1 -0
  132. package/dist/utils/nodeLoader.mjs +48 -0
  133. package/dist/utils/nodeLoader.mjs.map +1 -0
  134. package/dist/utils/templateResolver.d.ts +10 -0
  135. package/dist/utils/templateResolver.d.ts.map +1 -0
  136. package/dist/utils/templateResolver.mjs +64 -0
  137. package/dist/utils/templateResolver.mjs.map +1 -0
  138. package/dist/utils/topologicalSort.d.ts +10 -0
  139. package/dist/utils/topologicalSort.d.ts.map +1 -0
  140. package/dist/utils/topologicalSort.mjs +25 -0
  141. package/dist/utils/topologicalSort.mjs.map +1 -0
  142. package/nodes/alphafold_node/node.json +77 -0
  143. package/nodes/http_request_node/node.json +311 -0
  144. package/nodes/input_node/node.json +47 -0
  145. package/nodes/message_input_node/node.json +56 -0
  146. package/nodes/proteinmpnn_node/node.json +78 -0
  147. package/nodes/rfdiffusion_node/node.json +231 -0
  148. package/package.json +94 -0
@@ -0,0 +1,633 @@
1
+ import { create as b } from "zustand";
2
+ import { persist as N, createJSONStorage as C } from "../node_modules/zustand/esm/middleware.mjs";
3
+ import { topologicalSort as T } from "../utils/topologicalSort.mjs";
4
+ let h = {};
5
+ const B = (i) => {
6
+ h = i;
7
+ }, A = () => h;
8
+ let x = null;
9
+ const m = "novoprotein-pipeline-draft", S = "Unnamed Pipeline", v = (i, d) => {
10
+ x && clearTimeout(x), x = setTimeout(async () => {
11
+ var t;
12
+ const { currentPipeline: e } = i();
13
+ if (e) {
14
+ d({ isSaving: !0 });
15
+ try {
16
+ const n = {
17
+ ...e,
18
+ updatedAt: /* @__PURE__ */ new Date()
19
+ };
20
+ localStorage.setItem(m, JSON.stringify(n));
21
+ const r = A(), a = (t = r.authState) == null ? void 0 : t.user, s = r.apiClient;
22
+ if (a && s)
23
+ try {
24
+ await s.post("/pipelines", {
25
+ ...n,
26
+ status: "draft"
27
+ }), console.log("[debouncedAutoSave] Draft pipeline saved to backend");
28
+ } catch (o) {
29
+ console.error("[debouncedAutoSave] Failed to save draft to backend:", o);
30
+ }
31
+ d({
32
+ lastSavedAt: /* @__PURE__ */ new Date(),
33
+ isSaving: !1
34
+ });
35
+ } catch (n) {
36
+ console.error("Auto-save failed:", n), d({ isSaving: !1 });
37
+ }
38
+ }
39
+ }, 1e3);
40
+ }, $ = b()(
41
+ N(
42
+ (i, d) => ({
43
+ currentPipeline: null,
44
+ savedPipelines: [],
45
+ ghostBlueprint: null,
46
+ isExecuting: !1,
47
+ executionOrder: [],
48
+ currentExecution: null,
49
+ executionHistory: [],
50
+ viewMode: "editor",
51
+ selectedLogNodeId: null,
52
+ isPipelinesSidebarCollapsed: !1,
53
+ lastSavedAt: null,
54
+ isSaving: !1,
55
+ setCurrentPipeline: (e) => {
56
+ if (e) {
57
+ const { savedPipelines: t } = d(), n = t.findIndex((r) => r.id === e.id);
58
+ if (n >= 0) {
59
+ const r = [...t];
60
+ r[n] = e, i({ currentPipeline: e, savedPipelines: r });
61
+ } else
62
+ i({ currentPipeline: e });
63
+ v(d, i);
64
+ } else
65
+ i({ currentPipeline: null });
66
+ },
67
+ setGhostBlueprint: (e) => i({ ghostBlueprint: e }),
68
+ approveBlueprint: () => {
69
+ const { ghostBlueprint: e } = d();
70
+ if (!e) {
71
+ console.warn("[PipelineStore] approveBlueprint called but ghostBlueprint is null");
72
+ return;
73
+ }
74
+ const t = e.nodes.map((s, o) => ({
75
+ ...s,
76
+ status: "idle",
77
+ position: { x: 100 + o % 3 * 300, y: 100 + Math.floor(o / 3) * 200 }
78
+ })), n = {
79
+ id: `pipeline_${Date.now()}`,
80
+ name: S,
81
+ nodes: t,
82
+ edges: e.edges,
83
+ createdAt: /* @__PURE__ */ new Date(),
84
+ updatedAt: /* @__PURE__ */ new Date(),
85
+ status: "draft"
86
+ }, { savedPipelines: r } = d(), a = [...r, n];
87
+ console.log("[PipelineStore] approveBlueprint: Adding pipeline to savedPipelines", {
88
+ pipelineId: n.id,
89
+ pipelineName: n.name,
90
+ nodeCount: n.nodes.length,
91
+ currentSavedCount: r.length,
92
+ newSavedCount: a.length
93
+ }), i({
94
+ currentPipeline: n,
95
+ ghostBlueprint: null,
96
+ savedPipelines: a
97
+ }), v(d, i);
98
+ },
99
+ approveBlueprintWithSelection: (e, t) => {
100
+ const { ghostBlueprint: n } = d();
101
+ if (!n)
102
+ return console.warn("[PipelineStore] approveBlueprintWithSelection called but ghostBlueprint is null"), null;
103
+ const a = n.nodes.filter((P) => e.includes(P.id)).map((P, u) => ({
104
+ ...P,
105
+ config: { ...P.config, ...t[P.id] || {} },
106
+ status: "idle",
107
+ position: { x: 100 + u % 3 * 300, y: 100 + Math.floor(u / 3) * 200 }
108
+ })), s = new Set(e), o = n.edges.filter(
109
+ (P) => s.has(P.source) && s.has(P.target)
110
+ ), l = {
111
+ id: `pipeline_${Date.now()}`,
112
+ name: S,
113
+ nodes: a,
114
+ edges: o,
115
+ createdAt: /* @__PURE__ */ new Date(),
116
+ updatedAt: /* @__PURE__ */ new Date(),
117
+ status: "draft"
118
+ }, { savedPipelines: f } = d(), c = [...f, l];
119
+ return console.log("[PipelineStore] approveBlueprintWithSelection: Adding pipeline", {
120
+ pipelineId: l.id,
121
+ selectedNodeCount: a.length,
122
+ totalNodeCount: n.nodes.length
123
+ }), i({
124
+ currentPipeline: l,
125
+ ghostBlueprint: null,
126
+ savedPipelines: c
127
+ }), v(d, i), l;
128
+ },
129
+ rejectBlueprint: () => i({ ghostBlueprint: null }),
130
+ addNode: (e) => {
131
+ const { currentPipeline: t } = d();
132
+ if (t) {
133
+ const n = {
134
+ ...t,
135
+ nodes: [...t.nodes, e],
136
+ updatedAt: /* @__PURE__ */ new Date()
137
+ }, { savedPipelines: r } = d(), a = r.findIndex((s) => s.id === t.id);
138
+ if (a >= 0) {
139
+ const s = [...r];
140
+ s[a] = n, i({
141
+ currentPipeline: n,
142
+ savedPipelines: s
143
+ });
144
+ } else
145
+ i({ currentPipeline: n });
146
+ v(d, i);
147
+ } else {
148
+ const n = {
149
+ id: `pipeline_${Date.now()}`,
150
+ name: S,
151
+ nodes: [e],
152
+ edges: [],
153
+ createdAt: /* @__PURE__ */ new Date(),
154
+ updatedAt: /* @__PURE__ */ new Date(),
155
+ status: "draft"
156
+ }, { savedPipelines: r } = d();
157
+ i({
158
+ currentPipeline: n,
159
+ savedPipelines: [...r, n]
160
+ }), v(d, i);
161
+ }
162
+ },
163
+ updateNode: (e, t) => {
164
+ const { currentPipeline: n, savedPipelines: r } = d();
165
+ if (!n) return;
166
+ const a = {
167
+ ...n,
168
+ nodes: n.nodes.map((o) => {
169
+ if (o.id === e) {
170
+ const l = { ...o, ...t };
171
+ return t.config && o.config && (l.config = { ...o.config, ...t.config }), l;
172
+ }
173
+ return o;
174
+ }),
175
+ updatedAt: /* @__PURE__ */ new Date()
176
+ }, s = r.findIndex((o) => o.id === n.id);
177
+ if (s >= 0) {
178
+ const o = [...r];
179
+ o[s] = a, i({
180
+ currentPipeline: a,
181
+ savedPipelines: o
182
+ });
183
+ } else
184
+ i({ currentPipeline: a });
185
+ v(d, i);
186
+ },
187
+ deleteNode: (e) => {
188
+ const { currentPipeline: t, savedPipelines: n } = d();
189
+ if (!t) return;
190
+ const r = {
191
+ ...t,
192
+ nodes: t.nodes.filter((s) => s.id !== e),
193
+ edges: t.edges.filter(
194
+ (s) => s.source !== e && s.target !== e
195
+ ),
196
+ updatedAt: /* @__PURE__ */ new Date()
197
+ }, a = n.findIndex((s) => s.id === t.id);
198
+ if (a >= 0) {
199
+ const s = [...n];
200
+ s[a] = r, i({
201
+ currentPipeline: r,
202
+ savedPipelines: s
203
+ });
204
+ } else
205
+ i({ currentPipeline: r });
206
+ v(d, i);
207
+ },
208
+ addEdge: (e, t) => {
209
+ const { currentPipeline: n, savedPipelines: r } = d();
210
+ if (!n || n.edges.some(
211
+ (l) => l.source === e && l.target === t
212
+ )) return;
213
+ const s = {
214
+ ...n,
215
+ edges: [...n.edges, { source: e, target: t }],
216
+ updatedAt: /* @__PURE__ */ new Date()
217
+ }, o = r.findIndex((l) => l.id === n.id);
218
+ if (o >= 0) {
219
+ const l = [...r];
220
+ l[o] = s, i({
221
+ currentPipeline: s,
222
+ savedPipelines: l
223
+ });
224
+ } else
225
+ i({ currentPipeline: s });
226
+ v(d, i);
227
+ },
228
+ deleteEdge: (e, t) => {
229
+ const { currentPipeline: n, savedPipelines: r } = d();
230
+ if (!n) return;
231
+ const a = {
232
+ ...n,
233
+ edges: n.edges.filter(
234
+ (o) => !(o.source === e && o.target === t)
235
+ ),
236
+ updatedAt: /* @__PURE__ */ new Date()
237
+ }, s = r.findIndex((o) => o.id === n.id);
238
+ if (s >= 0) {
239
+ const o = [...r];
240
+ o[s] = a, i({
241
+ currentPipeline: a,
242
+ savedPipelines: o
243
+ });
244
+ } else
245
+ i({ currentPipeline: a });
246
+ v(d, i);
247
+ },
248
+ savePipeline: async (e, t, n, r) => {
249
+ var g;
250
+ const { currentPipeline: a, savedPipelines: s } = d();
251
+ if (!a) return;
252
+ const o = {
253
+ ...a,
254
+ name: e,
255
+ updatedAt: /* @__PURE__ */ new Date()
256
+ }, l = r || A(), f = (g = l.authState) == null ? void 0 : g.user, c = l.apiClient, P = l.sessionId;
257
+ if (f && c)
258
+ try {
259
+ const p = { ...o };
260
+ t && (p.message_id = t), n ? p.conversation_id = n : !n && t && P && (p.conversation_id = P), await c.post("/pipelines", p), console.log("Pipeline saved to backend", t ? `(linked to message ${t})` : "");
261
+ } catch (p) {
262
+ console.error("Failed to save pipeline to backend:", p);
263
+ }
264
+ const u = s.findIndex((p) => p.id === o.id);
265
+ if (u >= 0) {
266
+ const p = [...s];
267
+ p[u] = o, i({
268
+ savedPipelines: p,
269
+ lastSavedAt: /* @__PURE__ */ new Date()
270
+ });
271
+ } else
272
+ i({
273
+ savedPipelines: [...s, o],
274
+ lastSavedAt: /* @__PURE__ */ new Date()
275
+ });
276
+ try {
277
+ localStorage.setItem(m, JSON.stringify(o));
278
+ } catch (p) {
279
+ console.error("Failed to save draft:", p);
280
+ }
281
+ },
282
+ loadPipeline: async (e, t) => {
283
+ var l;
284
+ const { savedPipelines: n } = d(), r = t || A(), a = (l = r.authState) == null ? void 0 : l.user, s = r.apiClient;
285
+ if (a && s)
286
+ try {
287
+ const c = (await s.get(`/pipelines/${e}`)).data.pipeline;
288
+ c.createdAt && (c.createdAt = new Date(c.createdAt)), c.updatedAt && (c.updatedAt = new Date(c.updatedAt));
289
+ const P = n.findIndex((u) => u.id === e);
290
+ if (P >= 0) {
291
+ const u = [...n];
292
+ u[P] = c, i({ savedPipelines: u });
293
+ } else
294
+ i({ savedPipelines: [...n, c] });
295
+ i({
296
+ currentPipeline: { ...c },
297
+ lastSavedAt: c.updatedAt || /* @__PURE__ */ new Date()
298
+ });
299
+ return;
300
+ } catch (f) {
301
+ console.warn("Failed to load pipeline from backend, using local:", f);
302
+ }
303
+ const o = n.find((f) => f.id === e);
304
+ if (o) {
305
+ const f = o.updatedAt instanceof Date ? o.updatedAt : new Date(o.updatedAt);
306
+ i({
307
+ currentPipeline: { ...o },
308
+ lastSavedAt: isNaN(f.getTime()) ? /* @__PURE__ */ new Date() : f
309
+ });
310
+ }
311
+ },
312
+ deletePipeline: async (e, t) => {
313
+ var l;
314
+ const n = t || A(), r = (l = n.authState) == null ? void 0 : l.user, a = n.apiClient;
315
+ if (r && a && a.delete)
316
+ try {
317
+ await a.delete(`/pipelines/${e}`), console.log("Pipeline deleted from backend");
318
+ } catch (f) {
319
+ console.warn("Failed to delete pipeline from backend:", f);
320
+ }
321
+ else if (r && a)
322
+ try {
323
+ await a.post(`/pipelines/${e}`, {}, { headers: { "X-HTTP-Method-Override": "DELETE" } }), console.log("Pipeline deleted from backend");
324
+ } catch (f) {
325
+ console.warn("Failed to delete pipeline from backend:", f);
326
+ }
327
+ const { savedPipelines: s, currentPipeline: o } = d();
328
+ i({
329
+ savedPipelines: s.filter((f) => f.id !== e),
330
+ currentPipeline: (o == null ? void 0 : o.id) === e ? null : o
331
+ });
332
+ },
333
+ syncPipelines: async (e) => {
334
+ var a, s;
335
+ const t = e || A(), n = (a = t.authState) == null ? void 0 : a.user, r = t.apiClient;
336
+ if (!n || !r) {
337
+ console.log("[syncPipelines] User not authenticated or API client not available, skipping pipeline sync");
338
+ return;
339
+ }
340
+ try {
341
+ console.log("[syncPipelines] Fetching pipelines from backend for user:", n.id);
342
+ const o = await r.get("/pipelines");
343
+ console.log("[syncPipelines] API response:", o.data);
344
+ const l = o.data.pipelines || [];
345
+ console.log(`[syncPipelines] Found ${l.length} pipelines in backend`);
346
+ const c = (await Promise.all(
347
+ l.map(async (u) => {
348
+ try {
349
+ console.log(`[syncPipelines] Loading full pipeline data for: ${u.id}`);
350
+ const p = (await r.get(`/pipelines/${u.id}`)).data.pipeline;
351
+ return p.createdAt && (p.createdAt = new Date(p.createdAt)), p.updatedAt && (p.updatedAt = new Date(p.updatedAt)), console.log(`[syncPipelines] Successfully loaded pipeline: ${p.name || p.id}`), p;
352
+ } catch (g) {
353
+ return console.error(`[syncPipelines] Failed to load full pipeline ${u.id}:`, g), g.response && console.error(`[syncPipelines] Response status: ${g.response.status}`, g.response.data), null;
354
+ }
355
+ })
356
+ )).filter((u) => u !== null);
357
+ i({ savedPipelines: c }), console.log(`[syncPipelines] Synced ${c.length} pipelines from backend`);
358
+ const P = c.filter((u) => u.status === "draft");
359
+ if (P.length > 0) {
360
+ const u = P.reduce((g, p) => {
361
+ var D, y;
362
+ const w = ((D = g.updatedAt) == null ? void 0 : D.getTime()) || 0;
363
+ return (((y = p.updatedAt) == null ? void 0 : y.getTime()) || 0) > w ? p : g;
364
+ });
365
+ try {
366
+ const g = localStorage.getItem(m);
367
+ if (g) {
368
+ const p = JSON.parse(g), w = p.updatedAt ? new Date(p.updatedAt).getTime() : 0;
369
+ (((s = u.updatedAt) == null ? void 0 : s.getTime()) || 0) > w && (console.log("[syncPipelines] Loading draft from backend (newer than local)"), i({ currentPipeline: u }));
370
+ } else
371
+ console.log("[syncPipelines] Loading draft from backend (no local draft)"), i({ currentPipeline: u });
372
+ } catch (g) {
373
+ console.error("[syncPipelines] Failed to compare drafts:", g), i({ currentPipeline: u });
374
+ }
375
+ }
376
+ } catch (o) {
377
+ console.error("[syncPipelines] Failed to sync pipelines from backend:", o), o.response && (console.error("[syncPipelines] Response status:", o.response.status), console.error("[syncPipelines] Response data:", o.response.data));
378
+ }
379
+ },
380
+ startExecution: () => {
381
+ var a;
382
+ const { currentPipeline: e } = d();
383
+ if (!e) return;
384
+ const t = e.nodes.filter((s) => s.type === "input_node");
385
+ for (const s of t)
386
+ if (!((a = s.config) != null && a.filename)) {
387
+ const o = s.id;
388
+ i({
389
+ currentPipeline: {
390
+ ...e,
391
+ nodes: e.nodes.map(
392
+ (l) => l.id === o ? { ...l, status: "error", error: "No filename specified for input node" } : l
393
+ )
394
+ }
395
+ });
396
+ return;
397
+ }
398
+ const n = T(e.nodes, e.edges), r = {
399
+ id: `exec_${Date.now()}`,
400
+ startedAt: /* @__PURE__ */ new Date(),
401
+ status: "running",
402
+ logs: []
403
+ };
404
+ i({
405
+ isExecuting: !0,
406
+ executionOrder: n,
407
+ currentExecution: r,
408
+ // Don't auto-switch to executions view - stay in editor so users can see output
409
+ // viewMode: 'executions', // Removed - keep current view mode
410
+ currentPipeline: {
411
+ ...e,
412
+ status: "running",
413
+ nodes: e.nodes.map((s) => ({
414
+ ...s,
415
+ status: s.status === "success" || s.status === "completed" ? s.status : "pending"
416
+ }))
417
+ }
418
+ }), window.dispatchEvent(new CustomEvent("pipeline-started", {
419
+ detail: {
420
+ pipelineId: e.id,
421
+ status: "running",
422
+ nodes: e.nodes.map((s) => ({
423
+ id: s.id,
424
+ label: s.label,
425
+ status: s.status === "success" || s.status === "completed" ? s.status : "pending"
426
+ }))
427
+ }
428
+ }));
429
+ },
430
+ executeSingleNode: (e) => {
431
+ var o;
432
+ const { currentPipeline: t, addExecutionLog: n } = d();
433
+ if (!t) return;
434
+ const r = t.nodes.find((l) => l.id === e);
435
+ if (!r) return;
436
+ if (r.type === "input_node" && !((o = r.config) != null && o.filename)) {
437
+ i({
438
+ currentPipeline: {
439
+ ...t,
440
+ nodes: t.nodes.map(
441
+ (l) => l.id === e ? { ...l, status: "error", error: "No filename specified for input node" } : l
442
+ )
443
+ }
444
+ });
445
+ return;
446
+ }
447
+ const a = [e], s = {
448
+ id: `exec_${Date.now()}`,
449
+ startedAt: /* @__PURE__ */ new Date(),
450
+ status: "running",
451
+ logs: []
452
+ };
453
+ n({
454
+ nodeId: e,
455
+ nodeLabel: r.label,
456
+ nodeType: r.type,
457
+ status: "running"
458
+ }), i({
459
+ isExecuting: !0,
460
+ executionOrder: a,
461
+ currentExecution: s,
462
+ currentPipeline: {
463
+ ...t,
464
+ status: "running",
465
+ nodes: t.nodes.map(
466
+ (l) => l.id === e ? { ...l, status: "pending" } : l
467
+ )
468
+ }
469
+ });
470
+ },
471
+ stopExecution: () => {
472
+ const { currentPipeline: e, currentExecution: t, executionHistory: n } = d();
473
+ if (t) {
474
+ const r = {
475
+ ...t,
476
+ completedAt: /* @__PURE__ */ new Date(),
477
+ status: "stopped"
478
+ };
479
+ i({
480
+ executionHistory: [r, ...n].slice(0, 50),
481
+ // Keep last 50
482
+ // Keep currentExecution so users can view results after execution completes
483
+ // It will be cleared when a new execution starts
484
+ currentExecution: {
485
+ ...r,
486
+ status: "completed"
487
+ }
488
+ });
489
+ }
490
+ i({ isExecuting: !1 }), e && i({
491
+ currentPipeline: {
492
+ ...e,
493
+ status: "draft"
494
+ }
495
+ });
496
+ },
497
+ updateNodeStatus: (e, t, n) => {
498
+ const { currentPipeline: r, currentExecution: a } = d();
499
+ if (!r) return;
500
+ const s = r.nodes.find((l) => l.id === e), o = { status: t };
501
+ if (n && (o.error = n), (t === "success" || t === "completed") && !(s != null && s.result_metadata) && (o.result_metadata = {}), a && s) {
502
+ const l = a.logs.findIndex((c) => c.nodeId === e), f = /* @__PURE__ */ new Date();
503
+ if (l >= 0) {
504
+ const c = a.logs[l], P = {
505
+ ...c,
506
+ // Preserve all existing fields (request, response, input, output, etc.)
507
+ status: t,
508
+ error: n || c.error,
509
+ // Update error if provided, otherwise keep existing
510
+ completedAt: t === "success" || t === "error" ? c.completedAt || f : void 0,
511
+ duration: c.startedAt && (t === "success" || t === "error") ? c.duration || f.getTime() - new Date(c.startedAt).getTime() : c.duration
512
+ // Preserve existing duration if not completed
513
+ }, u = [...a.logs];
514
+ u[l] = P, i({
515
+ currentExecution: {
516
+ ...a,
517
+ logs: u
518
+ }
519
+ });
520
+ } else if (t === "running" || t === "pending") {
521
+ const c = {
522
+ nodeId: e,
523
+ nodeLabel: s.label,
524
+ nodeType: s.type,
525
+ status: t,
526
+ startedAt: f
527
+ };
528
+ i({
529
+ currentExecution: {
530
+ ...a,
531
+ logs: [...a.logs, c]
532
+ }
533
+ });
534
+ }
535
+ }
536
+ i({
537
+ currentPipeline: {
538
+ ...r,
539
+ nodes: r.nodes.map(
540
+ (l) => l.id === e ? { ...l, ...o } : l
541
+ ),
542
+ updatedAt: /* @__PURE__ */ new Date()
543
+ }
544
+ }), v(d, i);
545
+ },
546
+ clearPipeline: () => {
547
+ i({
548
+ currentPipeline: null,
549
+ ghostBlueprint: null,
550
+ isExecuting: !1,
551
+ executionOrder: [],
552
+ currentExecution: null,
553
+ lastSavedAt: null
554
+ });
555
+ try {
556
+ localStorage.removeItem(m);
557
+ } catch (e) {
558
+ console.error("Failed to clear draft:", e);
559
+ }
560
+ },
561
+ setViewMode: (e) => i({ viewMode: e }),
562
+ setSelectedLogNodeId: (e) => i({ selectedLogNodeId: e }),
563
+ setPipelinesSidebarCollapsed: (e) => i({ isPipelinesSidebarCollapsed: e }),
564
+ togglePipelinesSidebar: () => i((e) => ({ isPipelinesSidebarCollapsed: !e.isPipelinesSidebarCollapsed })),
565
+ addExecutionLog: (e) => {
566
+ const { currentExecution: t } = d();
567
+ if (!t) return;
568
+ const n = {
569
+ ...e,
570
+ startedAt: /* @__PURE__ */ new Date()
571
+ };
572
+ i({
573
+ currentExecution: {
574
+ ...t,
575
+ logs: [...t.logs, n]
576
+ }
577
+ });
578
+ },
579
+ updateExecutionLog: (e, t) => {
580
+ const { currentExecution: n } = d();
581
+ if (!n) return;
582
+ const r = n.logs.findIndex((s) => s.nodeId === e);
583
+ if (r === -1) return;
584
+ const a = [...n.logs];
585
+ a[r] = { ...a[r], ...t }, i({
586
+ currentExecution: {
587
+ ...n,
588
+ logs: a
589
+ }
590
+ });
591
+ }
592
+ }),
593
+ {
594
+ name: "novoprotein-pipeline-storage",
595
+ version: 1,
596
+ storage: C(() => localStorage),
597
+ partialize: (i) => ({
598
+ // Persist all pipelines including unnamed ones
599
+ savedPipelines: i.savedPipelines
600
+ // Don't persist currentPipeline or execution state - it's saved as draft separately
601
+ }),
602
+ // Load draft on initialization
603
+ onRehydrateStorage: () => (i) => {
604
+ if (i) {
605
+ try {
606
+ i.savedPipelines = i.savedPipelines.map((e) => (e.createdAt && typeof e.createdAt == "string" && (e.createdAt = new Date(e.createdAt)), e.updatedAt && typeof e.updatedAt == "string" && (e.updatedAt = new Date(e.updatedAt)), e));
607
+ const d = localStorage.getItem(m);
608
+ if (d) {
609
+ const e = JSON.parse(d);
610
+ if (i.setCurrentPipeline(e), e.updatedAt) {
611
+ const t = e.updatedAt instanceof Date ? e.updatedAt : new Date(e.updatedAt);
612
+ i.lastSavedAt = isNaN(t.getTime()) ? /* @__PURE__ */ new Date() : t;
613
+ } else
614
+ i.lastSavedAt = /* @__PURE__ */ new Date();
615
+ }
616
+ } catch (d) {
617
+ console.error("Failed to load draft:", d);
618
+ }
619
+ setTimeout(() => {
620
+ var n;
621
+ const d = A(), e = (n = d.authState) == null ? void 0 : n.user, t = d.apiClient;
622
+ e && t && i.syncPipelines && i.syncPipelines({ apiClient: t, authState: d.authState }).catch(console.error);
623
+ }, 1e3);
624
+ }
625
+ }
626
+ }
627
+ )
628
+ );
629
+ export {
630
+ B as setPipelineDependencies,
631
+ $ as usePipelineStore
632
+ };
633
+ //# sourceMappingURL=pipelineStore.mjs.map