@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,189 @@
1
+ import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
+ import { usePipelineStore as w } from "../store/pipelineStore.mjs";
3
+ import { Loader2 as x, CheckCircle2 as f, FileInput as p, ChevronRight as L, Clock as I, ExternalLink as S, ChevronDown as g, XCircle as j, Atom as C, Dna as $, Sparkles as _ } from "lucide-react";
4
+ const N = (t) => {
5
+ switch (t) {
6
+ case "input_node":
7
+ return /* @__PURE__ */ e(p, { className: "w-4 h-4" });
8
+ case "rfdiffusion_node":
9
+ return /* @__PURE__ */ e(_, { className: "w-4 h-4" });
10
+ case "proteinmpnn_node":
11
+ return /* @__PURE__ */ e($, { className: "w-4 h-4" });
12
+ case "alphafold_node":
13
+ return /* @__PURE__ */ e(C, { className: "w-4 h-4" });
14
+ default:
15
+ return /* @__PURE__ */ e("div", { className: "w-4 h-4 rounded bg-gray-600" });
16
+ }
17
+ }, b = (t) => {
18
+ switch (t) {
19
+ case "input_node":
20
+ return "text-blue-400";
21
+ case "rfdiffusion_node":
22
+ return "text-purple-400";
23
+ case "proteinmpnn_node":
24
+ return "text-green-400";
25
+ case "alphafold_node":
26
+ return "text-orange-400";
27
+ default:
28
+ return "text-gray-400";
29
+ }
30
+ }, i = (t) => {
31
+ if (t < 1e3) return `${t}ms`;
32
+ if (t < 6e4) return `${(t / 1e3).toFixed(1)}s`;
33
+ const s = Math.floor(t / 6e4), n = Math.floor(t % 6e4 / 1e3);
34
+ return `${s}m ${n}s`;
35
+ }, y = (t) => new Date(t).toLocaleTimeString("en-US", {
36
+ hour: "2-digit",
37
+ minute: "2-digit",
38
+ second: "2-digit",
39
+ hour12: !1
40
+ }), T = ({ log: t, isSelected: s, onSelect: n }) => /* @__PURE__ */ a(
41
+ "div",
42
+ {
43
+ onClick: n,
44
+ className: `
45
+ group flex items-center gap-3 px-3 py-2.5 cursor-pointer transition-all animate-slide-in
46
+ ${s ? "bg-blue-500/10 border-l-2 border-blue-400" : "hover:bg-gray-700/30 border-l-2 border-transparent"}
47
+ `,
48
+ children: [
49
+ (() => {
50
+ switch (t.status) {
51
+ case "running":
52
+ return /* @__PURE__ */ a("div", { className: "relative", children: [
53
+ /* @__PURE__ */ e("div", { className: "w-5 h-5 rounded-full bg-blue-500/20 flex items-center justify-center", children: /* @__PURE__ */ e(x, { className: "w-3 h-3 animate-spin text-blue-400" }) }),
54
+ /* @__PURE__ */ e("div", { className: "absolute inset-0 rounded-full bg-blue-500/30 animate-ping" })
55
+ ] });
56
+ case "success":
57
+ return /* @__PURE__ */ e("div", { className: "w-5 h-5 rounded-full bg-green-500/20 flex items-center justify-center", children: /* @__PURE__ */ e(f, { className: "w-3 h-3 text-green-400" }) });
58
+ case "error":
59
+ return /* @__PURE__ */ e("div", { className: "w-5 h-5 rounded-full bg-red-500/20 flex items-center justify-center", children: /* @__PURE__ */ e(j, { className: "w-3 h-3 text-red-400" }) });
60
+ case "pending":
61
+ return /* @__PURE__ */ e("div", { className: "w-5 h-5 rounded-full bg-gray-600/20 flex items-center justify-center", children: /* @__PURE__ */ e("div", { className: "w-2 h-2 rounded-full bg-gray-500" }) });
62
+ default:
63
+ return /* @__PURE__ */ e("div", { className: "w-5 h-5 rounded-full bg-gray-600/20 flex items-center justify-center", children: /* @__PURE__ */ e("div", { className: "w-2 h-2 rounded-full bg-gray-500" }) });
64
+ }
65
+ })(),
66
+ /* @__PURE__ */ e("div", { className: `${b(t.nodeType)}`, children: N(t.nodeType) }),
67
+ /* @__PURE__ */ e("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ e("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ e("span", { className: `text-sm font-medium truncate ${s ? "text-gray-100" : "text-gray-300"}`, children: t.nodeLabel }) }) }),
68
+ t.duration !== void 0 && /* @__PURE__ */ e("span", { className: "text-xs text-gray-500 font-mono", children: i(t.duration) }),
69
+ /* @__PURE__ */ e(L, { className: `w-4 h-4 text-gray-500 transition-transform ${s ? "rotate-90" : ""}` })
70
+ ]
71
+ }
72
+ ), k = ({ log: t }) => /* @__PURE__ */ a("div", { className: "border-l border-gray-700/50 bg-[#1a1a2e] flex flex-col h-full", children: [
73
+ /* @__PURE__ */ a("div", { className: "px-4 py-3 border-b border-gray-700/50 bg-[#1e1e32]", children: [
74
+ /* @__PURE__ */ a("div", { className: "flex items-center gap-2", children: [
75
+ /* @__PURE__ */ e("div", { className: b(t.nodeType), children: N(t.nodeType) }),
76
+ /* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-gray-200", children: t.nodeLabel })
77
+ ] }),
78
+ /* @__PURE__ */ a("div", { className: "flex items-center gap-4 mt-2 text-xs text-gray-500", children: [
79
+ t.duration !== void 0 && /* @__PURE__ */ a("div", { className: "flex items-center gap-1", children: [
80
+ /* @__PURE__ */ e(I, { className: "w-3 h-3" }),
81
+ /* @__PURE__ */ e("span", { children: i(t.duration) })
82
+ ] }),
83
+ t.startedAt && /* @__PURE__ */ a("span", { children: [
84
+ "Started at ",
85
+ y(t.startedAt)
86
+ ] })
87
+ ] }),
88
+ (t.status === "success" || t.status === "completed") && /* @__PURE__ */ a("button", { className: "mt-2 flex items-center gap-1 text-xs text-blue-400 hover:text-blue-300 transition-colors", children: [
89
+ /* @__PURE__ */ e(S, { className: "w-3 h-3" }),
90
+ "View sub-execution"
91
+ ] })
92
+ ] }),
93
+ /* @__PURE__ */ a("div", { className: "px-4 py-3 border-b border-gray-700/50", children: [
94
+ /* @__PURE__ */ a("button", { className: "flex items-center gap-2 w-full", children: [
95
+ /* @__PURE__ */ e(g, { className: "w-4 h-4 text-gray-500" }),
96
+ /* @__PURE__ */ e("span", { className: "text-sm font-medium text-gray-300", children: "Input" })
97
+ ] }),
98
+ /* @__PURE__ */ e("div", { className: "mt-3 bg-gray-900/50 rounded-lg p-3 text-xs font-mono text-gray-400 overflow-x-auto border border-gray-700/30", children: /* @__PURE__ */ e("pre", { className: "whitespace-pre-wrap", children: JSON.stringify(t.input || { query: { message: "..." } }, null, 2) }) })
99
+ ] }),
100
+ /* @__PURE__ */ a("div", { className: "px-4 py-3 flex-1 overflow-y-auto", children: [
101
+ /* @__PURE__ */ a("button", { className: "flex items-center gap-2 w-full", children: [
102
+ /* @__PURE__ */ e(g, { className: "w-4 h-4 text-gray-500" }),
103
+ /* @__PURE__ */ e("span", { className: "text-sm font-medium text-gray-300", children: "Output" })
104
+ ] }),
105
+ /* @__PURE__ */ e("div", { className: "mt-3 bg-gray-900/50 rounded-lg p-3 text-xs font-mono text-gray-400 overflow-x-auto border border-gray-700/30", children: /* @__PURE__ */ e("pre", { className: "whitespace-pre-wrap", children: t.error ? /* @__PURE__ */ e("span", { className: "text-red-400", children: JSON.stringify({ error: t.error }, null, 2) }) : JSON.stringify(t.output || { message: "..." }, null, 2) }) })
106
+ ] })
107
+ ] }), J = () => {
108
+ const {
109
+ currentPipeline: t,
110
+ currentExecution: s,
111
+ selectedLogNodeId: n,
112
+ setSelectedLogNodeId: c,
113
+ isExecuting: d
114
+ } = w(), o = (s == null ? void 0 : s.logs) || [], l = o.length > 0 ? o : (t == null ? void 0 : t.nodes.map((r) => ({
115
+ nodeId: r.id,
116
+ nodeLabel: r.label,
117
+ nodeType: r.type,
118
+ status: r.status
119
+ }))) || [], m = l.find((r) => r.nodeId === n), u = l.filter((r) => r.status === "success" || r.status === "completed").length, h = l.reduce((r, v) => r + (v.duration || 0), 0);
120
+ return /* @__PURE__ */ a("div", { className: "h-full flex flex-col bg-[#1e1e32]", children: [
121
+ /* @__PURE__ */ a("div", { className: "px-4 py-3 border-b border-gray-700/50 bg-gradient-to-r from-[#1a1a2e] to-[#1e1e32]", children: [
122
+ /* @__PURE__ */ a("div", { className: "flex items-center justify-between", children: [
123
+ /* @__PURE__ */ a("div", { children: [
124
+ /* @__PURE__ */ e("span", { className: "text-sm font-semibold text-gray-200", children: d ? "Running..." : s ? "Execution Complete" : "Logs from Pipeline" }),
125
+ h > 0 && /* @__PURE__ */ a("span", { className: "ml-2 text-xs text-gray-500", children: [
126
+ "| ",
127
+ i(h)
128
+ ] }),
129
+ (s == null ? void 0 : s.startedAt) && /* @__PURE__ */ a("span", { className: "ml-2 text-xs text-gray-500", children: [
130
+ "| Started at ",
131
+ y(s.startedAt)
132
+ ] })
133
+ ] }),
134
+ /* @__PURE__ */ a("div", { className: "flex items-center gap-2", children: [
135
+ /* @__PURE__ */ a("span", { className: "text-xs text-gray-500", children: [
136
+ u,
137
+ " / ",
138
+ l.length,
139
+ " nodes"
140
+ ] }),
141
+ d && /* @__PURE__ */ a("span", { className: "relative flex h-2 w-2", children: [
142
+ /* @__PURE__ */ e("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75" }),
143
+ /* @__PURE__ */ e("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500" })
144
+ ] })
145
+ ] })
146
+ ] }),
147
+ l.length > 0 && /* @__PURE__ */ e("div", { className: "mt-3 w-full bg-gray-700/50 rounded-full h-1.5 overflow-hidden", children: /* @__PURE__ */ e(
148
+ "div",
149
+ {
150
+ className: `h-1.5 rounded-full transition-all duration-500 ${d ? "bg-blue-500 animate-shimmer" : "bg-green-500"}`,
151
+ style: { width: `${u / l.length * 100}%` }
152
+ }
153
+ ) })
154
+ ] }),
155
+ /* @__PURE__ */ a("div", { className: "flex-1 flex min-h-0", children: [
156
+ /* @__PURE__ */ a("div", { className: "w-64 border-r border-gray-700/50 flex flex-col bg-[#1a1a2e]/50", children: [
157
+ /* @__PURE__ */ e("div", { className: "px-3 py-2.5 bg-gray-800/30 border-b border-gray-700/50", children: /* @__PURE__ */ a("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: [
158
+ "Latest Logs from ",
159
+ (t == null ? void 0 : t.name) || "Pipeline"
160
+ ] }) }),
161
+ /* @__PURE__ */ a("div", { className: "flex-1 overflow-y-auto", children: [
162
+ /* @__PURE__ */ a("div", { className: "px-3 py-2.5 flex items-center gap-2 bg-gray-800/20 border-b border-gray-700/30", children: [
163
+ /* @__PURE__ */ e("div", { className: "w-5 h-5 rounded bg-green-500/20 flex items-center justify-center", children: d ? /* @__PURE__ */ e(x, { className: "w-3 h-3 animate-spin text-green-400" }) : /* @__PURE__ */ e(f, { className: "w-3 h-3 text-green-400" }) }),
164
+ /* @__PURE__ */ e("span", { className: "text-sm font-medium text-gray-300", children: (t == null ? void 0 : t.name) || "Pipeline" })
165
+ ] }),
166
+ /* @__PURE__ */ e("div", { className: "pl-2", children: l.map((r) => /* @__PURE__ */ e(
167
+ T,
168
+ {
169
+ log: r,
170
+ isSelected: n === r.nodeId,
171
+ onSelect: () => c(
172
+ n === r.nodeId ? null : r.nodeId
173
+ )
174
+ },
175
+ r.nodeId
176
+ )) })
177
+ ] })
178
+ ] }),
179
+ /* @__PURE__ */ e("div", { className: "flex-1 min-w-0", children: m ? /* @__PURE__ */ e(k, { log: m }) : /* @__PURE__ */ e("div", { className: "h-full flex items-center justify-center bg-[#1a1a2e]", children: /* @__PURE__ */ a("div", { className: "text-center", children: [
180
+ /* @__PURE__ */ e("div", { className: "w-12 h-12 rounded-full bg-gray-800/50 flex items-center justify-center mx-auto mb-3", children: /* @__PURE__ */ e(p, { className: "w-5 h-5 text-gray-600" }) }),
181
+ /* @__PURE__ */ e("p", { className: "text-sm text-gray-500", children: "Select a node to view execution details" })
182
+ ] }) }) })
183
+ ] })
184
+ ] });
185
+ };
186
+ export {
187
+ J as ExecutionLogsPanel
188
+ };
189
+ //# sourceMappingURL=ExecutionLogsPanel.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExecutionLogsPanel.mjs","sources":["../../components/ExecutionLogsPanel.tsx"],"sourcesContent":["import React from 'react';\nimport { usePipelineStore, ExecutionLogEntry } from '../store/pipelineStore';\nimport { \n Loader2, \n CheckCircle2, \n XCircle, \n Clock, \n ChevronRight, \n ChevronDown,\n ExternalLink,\n FileInput,\n Sparkles,\n Dna,\n Atom\n} from 'lucide-react';\n\n// Get icon for node type\nconst getNodeIcon = (type: string) => {\n switch (type) {\n case 'input_node':\n return <FileInput className=\"w-4 h-4\" />;\n case 'rfdiffusion_node':\n return <Sparkles className=\"w-4 h-4\" />;\n case 'proteinmpnn_node':\n return <Dna className=\"w-4 h-4\" />;\n case 'alphafold_node':\n return <Atom className=\"w-4 h-4\" />;\n default:\n return <div className=\"w-4 h-4 rounded bg-gray-600\" />;\n }\n};\n\n// Get color class for node type\nconst getNodeColor = (type: string) => {\n switch (type) {\n case 'input_node':\n return 'text-blue-400';\n case 'rfdiffusion_node':\n return 'text-purple-400';\n case 'proteinmpnn_node':\n return 'text-green-400';\n case 'alphafold_node':\n return 'text-orange-400';\n default:\n return 'text-gray-400';\n }\n};\n\n// Format duration\nconst formatDuration = (ms: number) => {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.floor((ms % 60000) / 1000);\n return `${minutes}m ${seconds}s`;\n};\n\n// Format time\nconst formatTime = (date: Date) => {\n return new Date(date).toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n });\n};\n\ninterface LogNodeItemProps {\n log: ExecutionLogEntry;\n isSelected: boolean;\n onSelect: () => void;\n}\n\nconst LogNodeItem: React.FC<LogNodeItemProps> = ({ log, isSelected, onSelect }) => {\n const getStatusIndicator = () => {\n switch (log.status) {\n case 'running':\n return (\n <div className=\"relative\">\n <div className=\"w-5 h-5 rounded-full bg-blue-500/20 flex items-center justify-center\">\n <Loader2 className=\"w-3 h-3 animate-spin text-blue-400\" />\n </div>\n <div className=\"absolute inset-0 rounded-full bg-blue-500/30 animate-ping\" />\n </div>\n );\n case 'success':\n return (\n <div className=\"w-5 h-5 rounded-full bg-green-500/20 flex items-center justify-center\">\n <CheckCircle2 className=\"w-3 h-3 text-green-400\" />\n </div>\n );\n case 'error':\n return (\n <div className=\"w-5 h-5 rounded-full bg-red-500/20 flex items-center justify-center\">\n <XCircle className=\"w-3 h-3 text-red-400\" />\n </div>\n );\n case 'pending':\n return (\n <div className=\"w-5 h-5 rounded-full bg-gray-600/20 flex items-center justify-center\">\n <div className=\"w-2 h-2 rounded-full bg-gray-500\" />\n </div>\n );\n default:\n return (\n <div className=\"w-5 h-5 rounded-full bg-gray-600/20 flex items-center justify-center\">\n <div className=\"w-2 h-2 rounded-full bg-gray-500\" />\n </div>\n );\n }\n };\n\n return (\n <div\n onClick={onSelect}\n className={`\n group flex items-center gap-3 px-3 py-2.5 cursor-pointer transition-all animate-slide-in\n ${isSelected \n ? 'bg-blue-500/10 border-l-2 border-blue-400' \n : 'hover:bg-gray-700/30 border-l-2 border-transparent'\n }\n `}\n >\n {/* Status indicator */}\n {getStatusIndicator()}\n \n {/* Node icon and label */}\n <div className={`${getNodeColor(log.nodeType)}`}>\n {getNodeIcon(log.nodeType)}\n </div>\n \n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className={`text-sm font-medium truncate ${isSelected ? 'text-gray-100' : 'text-gray-300'}`}>\n {log.nodeLabel}\n </span>\n </div>\n </div>\n \n {/* Duration badge */}\n {log.duration !== undefined && (\n <span className=\"text-xs text-gray-500 font-mono\">\n {formatDuration(log.duration)}\n </span>\n )}\n \n {/* Expand indicator */}\n <ChevronRight className={`w-4 h-4 text-gray-500 transition-transform ${isSelected ? 'rotate-90' : ''}`} />\n </div>\n );\n};\n\ninterface LogDetailsPanelProps {\n log: ExecutionLogEntry;\n}\n\nconst LogDetailsPanel: React.FC<LogDetailsPanelProps> = ({ log }) => {\n return (\n <div className=\"border-l border-gray-700/50 bg-[#1a1a2e] flex flex-col h-full\">\n {/* Header */}\n <div className=\"px-4 py-3 border-b border-gray-700/50 bg-[#1e1e32]\">\n <div className=\"flex items-center gap-2\">\n <div className={getNodeColor(log.nodeType)}>\n {getNodeIcon(log.nodeType)}\n </div>\n <h3 className=\"text-sm font-semibold text-gray-200\">{log.nodeLabel}</h3>\n </div>\n \n {/* Timing info */}\n <div className=\"flex items-center gap-4 mt-2 text-xs text-gray-500\">\n {log.duration !== undefined && (\n <div className=\"flex items-center gap-1\">\n <Clock className=\"w-3 h-3\" />\n <span>{formatDuration(log.duration)}</span>\n </div>\n )}\n {log.startedAt && (\n <span>Started at {formatTime(log.startedAt)}</span>\n )}\n </div>\n \n {/* View sub-execution link */}\n {(log.status === 'success' || log.status === 'completed') && (\n <button className=\"mt-2 flex items-center gap-1 text-xs text-blue-400 hover:text-blue-300 transition-colors\">\n <ExternalLink className=\"w-3 h-3\" />\n View sub-execution\n </button>\n )}\n </div>\n \n {/* Input section */}\n <div className=\"px-4 py-3 border-b border-gray-700/50\">\n <button className=\"flex items-center gap-2 w-full\">\n <ChevronDown className=\"w-4 h-4 text-gray-500\" />\n <span className=\"text-sm font-medium text-gray-300\">Input</span>\n </button>\n <div className=\"mt-3 bg-gray-900/50 rounded-lg p-3 text-xs font-mono text-gray-400 overflow-x-auto border border-gray-700/30\">\n <pre className=\"whitespace-pre-wrap\">\n {JSON.stringify(log.input || { query: { message: \"...\" } }, null, 2)}\n </pre>\n </div>\n </div>\n \n {/* Output section */}\n <div className=\"px-4 py-3 flex-1 overflow-y-auto\">\n <button className=\"flex items-center gap-2 w-full\">\n <ChevronDown className=\"w-4 h-4 text-gray-500\" />\n <span className=\"text-sm font-medium text-gray-300\">Output</span>\n </button>\n <div className=\"mt-3 bg-gray-900/50 rounded-lg p-3 text-xs font-mono text-gray-400 overflow-x-auto border border-gray-700/30\">\n <pre className=\"whitespace-pre-wrap\">\n {log.error \n ? <span className=\"text-red-400\">{JSON.stringify({ error: log.error }, null, 2)}</span>\n : JSON.stringify(log.output || { message: \"...\" }, null, 2)\n }\n </pre>\n </div>\n </div>\n </div>\n );\n};\n\nexport const ExecutionLogsPanel: React.FC = () => {\n const { \n currentPipeline, \n currentExecution, \n selectedLogNodeId, \n setSelectedLogNodeId,\n isExecuting \n } = usePipelineStore();\n\n // Build execution tree from logs\n const executionLogs = currentExecution?.logs || [];\n \n // If not executing and no logs, show pending nodes\n const displayLogs: ExecutionLogEntry[] = executionLogs.length > 0 \n ? executionLogs \n : (currentPipeline?.nodes.map(node => ({\n nodeId: node.id,\n nodeLabel: node.label,\n nodeType: node.type,\n status: node.status,\n })) || []);\n\n const selectedLog = displayLogs.find(l => l.nodeId === selectedLogNodeId);\n\n // Calculate execution summary\n const completedCount = displayLogs.filter(l => l.status === 'success' || l.status === 'completed').length;\n const totalDuration = displayLogs.reduce((acc, l) => acc + (l.duration || 0), 0);\n\n return (\n <div className=\"h-full flex flex-col bg-[#1e1e32]\">\n {/* Header with execution summary */}\n <div className=\"px-4 py-3 border-b border-gray-700/50 bg-gradient-to-r from-[#1a1a2e] to-[#1e1e32]\">\n <div className=\"flex items-center justify-between\">\n <div>\n <span className=\"text-sm font-semibold text-gray-200\">\n {isExecuting ? 'Running...' : currentExecution ? 'Execution Complete' : 'Logs from Pipeline'}\n </span>\n {totalDuration > 0 && (\n <span className=\"ml-2 text-xs text-gray-500\">\n | {formatDuration(totalDuration)}\n </span>\n )}\n {currentExecution?.startedAt && (\n <span className=\"ml-2 text-xs text-gray-500\">\n | Started at {formatTime(currentExecution.startedAt)}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-gray-500\">\n {completedCount} / {displayLogs.length} nodes\n </span>\n {isExecuting && (\n <span className=\"relative flex h-2 w-2\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75\"></span>\n <span className=\"relative inline-flex rounded-full h-2 w-2 bg-green-500\"></span>\n </span>\n )}\n </div>\n </div>\n \n {/* Progress bar */}\n {displayLogs.length > 0 && (\n <div className=\"mt-3 w-full bg-gray-700/50 rounded-full h-1.5 overflow-hidden\">\n <div \n className={`h-1.5 rounded-full transition-all duration-500 ${\n isExecuting ? 'bg-blue-500 animate-shimmer' : 'bg-green-500'\n }`}\n style={{ width: `${(completedCount / displayLogs.length) * 100}%` }}\n />\n </div>\n )}\n </div>\n\n {/* Main content area */}\n <div className=\"flex-1 flex min-h-0\">\n {/* Left: Execution tree */}\n <div className=\"w-64 border-r border-gray-700/50 flex flex-col bg-[#1a1a2e]/50\">\n <div className=\"px-3 py-2.5 bg-gray-800/30 border-b border-gray-700/50\">\n <span className=\"text-xs font-medium text-gray-500 uppercase tracking-wider\">\n Latest Logs from {currentPipeline?.name || 'Pipeline'}\n </span>\n </div>\n <div className=\"flex-1 overflow-y-auto\">\n {/* Pipeline root */}\n <div className=\"px-3 py-2.5 flex items-center gap-2 bg-gray-800/20 border-b border-gray-700/30\">\n <div className=\"w-5 h-5 rounded bg-green-500/20 flex items-center justify-center\">\n {isExecuting ? (\n <Loader2 className=\"w-3 h-3 animate-spin text-green-400\" />\n ) : (\n <CheckCircle2 className=\"w-3 h-3 text-green-400\" />\n )}\n </div>\n <span className=\"text-sm font-medium text-gray-300\">\n {currentPipeline?.name || 'Pipeline'}\n </span>\n </div>\n \n {/* Node logs - indented like a tree */}\n <div className=\"pl-2\">\n {displayLogs.map((log) => (\n <LogNodeItem\n key={log.nodeId}\n log={log}\n isSelected={selectedLogNodeId === log.nodeId}\n onSelect={() => setSelectedLogNodeId(\n selectedLogNodeId === log.nodeId ? null : log.nodeId\n )}\n />\n ))}\n </div>\n </div>\n </div>\n\n {/* Right: Log details */}\n <div className=\"flex-1 min-w-0\">\n {selectedLog ? (\n <LogDetailsPanel log={selectedLog} />\n ) : (\n <div className=\"h-full flex items-center justify-center bg-[#1a1a2e]\">\n <div className=\"text-center\">\n <div className=\"w-12 h-12 rounded-full bg-gray-800/50 flex items-center justify-center mx-auto mb-3\">\n <FileInput className=\"w-5 h-5 text-gray-600\" />\n </div>\n <p className=\"text-sm text-gray-500\">Select a node to view execution details</p>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n"],"names":["getNodeIcon","type","jsx","FileInput","Sparkles","Dna","Atom","getNodeColor","formatDuration","ms","minutes","seconds","formatTime","date","LogNodeItem","log","isSelected","onSelect","jsxs","Loader2","CheckCircle2","XCircle","ChevronRight","LogDetailsPanel","Clock","ExternalLink","ChevronDown","ExecutionLogsPanel","currentPipeline","currentExecution","selectedLogNodeId","setSelectedLogNodeId","isExecuting","usePipelineStore","executionLogs","displayLogs","node","selectedLog","l","completedCount","totalDuration","acc"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ interface NodeContextMenuProps {
3
+ x: number;
4
+ y: number;
5
+ nodeId: string;
6
+ nodeLabel: string;
7
+ onRename: () => void;
8
+ onDelete: () => void;
9
+ onConfigure: () => void;
10
+ onDuplicate: () => void;
11
+ onClose: () => void;
12
+ }
13
+ export declare const NodeContextMenu: React.FC<NodeContextMenuProps>;
14
+ export {};
15
+ //# sourceMappingURL=NodeContextMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeContextMenu.d.ts","sourceRoot":"","sources":["../../components/NodeContextMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAGjD,UAAU,oBAAoB;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAiH1D,CAAC"}
@@ -0,0 +1,110 @@
1
+ import { jsxs as n, jsx as e } from "react/jsx-runtime";
2
+ import { useRef as g, useEffect as y } from "react";
3
+ import { X as b, Edit2 as w, Settings as v, Copy as N, Trash2 as k } from "lucide-react";
4
+ const I = ({
5
+ x: i,
6
+ y: d,
7
+ nodeId: C,
8
+ nodeLabel: l,
9
+ onRename: m,
10
+ onDelete: x,
11
+ onConfigure: p,
12
+ onDuplicate: u,
13
+ onClose: r
14
+ }) => {
15
+ const o = g(null);
16
+ y(() => {
17
+ const t = (a) => {
18
+ o.current && !o.current.contains(a.target) && r();
19
+ }, c = (a) => {
20
+ a.key === "Escape" && r();
21
+ }, h = setTimeout(() => {
22
+ document.addEventListener("mousedown", t), document.addEventListener("keydown", c);
23
+ }, 10);
24
+ return () => {
25
+ clearTimeout(h), document.removeEventListener("mousedown", t), document.removeEventListener("keydown", c);
26
+ };
27
+ }, [r]);
28
+ const f = (t) => {
29
+ t.preventDefault(), t.stopPropagation();
30
+ }, s = (t) => {
31
+ t(), r();
32
+ };
33
+ return /* @__PURE__ */ n(
34
+ "div",
35
+ {
36
+ ref: o,
37
+ className: "fixed z-50 bg-[#1e1e32] border border-gray-700 rounded-lg shadow-xl py-1 min-w-[180px]",
38
+ style: {
39
+ left: `${i}px`,
40
+ top: `${d}px`
41
+ },
42
+ onContextMenu: f,
43
+ children: [
44
+ /* @__PURE__ */ n("div", { className: "px-3 py-2 border-b border-gray-700/50 flex items-center justify-between", children: [
45
+ /* @__PURE__ */ e("span", { className: "text-xs font-medium text-gray-300 truncate max-w-[140px]", title: l, children: l }),
46
+ /* @__PURE__ */ e(
47
+ "button",
48
+ {
49
+ onClick: r,
50
+ className: "p-0.5 text-gray-500 hover:text-gray-300 rounded transition-colors",
51
+ title: "Close",
52
+ children: /* @__PURE__ */ e(b, { className: "w-3 h-3" })
53
+ }
54
+ )
55
+ ] }),
56
+ /* @__PURE__ */ n("div", { className: "py-1", children: [
57
+ /* @__PURE__ */ n(
58
+ "button",
59
+ {
60
+ onClick: () => s(m),
61
+ className: "w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-800/50 flex items-center gap-2 transition-colors",
62
+ children: [
63
+ /* @__PURE__ */ e(w, { className: "w-4 h-4" }),
64
+ /* @__PURE__ */ e("span", { children: "Rename" })
65
+ ]
66
+ }
67
+ ),
68
+ /* @__PURE__ */ n(
69
+ "button",
70
+ {
71
+ onClick: () => s(p),
72
+ className: "w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-800/50 flex items-center gap-2 transition-colors",
73
+ children: [
74
+ /* @__PURE__ */ e(v, { className: "w-4 h-4" }),
75
+ /* @__PURE__ */ e("span", { children: "Configure" })
76
+ ]
77
+ }
78
+ ),
79
+ /* @__PURE__ */ n(
80
+ "button",
81
+ {
82
+ onClick: () => s(u),
83
+ className: "w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-800/50 flex items-center gap-2 transition-colors",
84
+ children: [
85
+ /* @__PURE__ */ e(N, { className: "w-4 h-4" }),
86
+ /* @__PURE__ */ e("span", { children: "Duplicate" })
87
+ ]
88
+ }
89
+ ),
90
+ /* @__PURE__ */ e("div", { className: "my-1 border-t border-gray-700/50" }),
91
+ /* @__PURE__ */ n(
92
+ "button",
93
+ {
94
+ onClick: () => s(x),
95
+ className: "w-full px-3 py-2 text-left text-sm text-red-400 hover:bg-red-500/10 flex items-center gap-2 transition-colors",
96
+ children: [
97
+ /* @__PURE__ */ e(k, { className: "w-4 h-4" }),
98
+ /* @__PURE__ */ e("span", { children: "Delete" })
99
+ ]
100
+ }
101
+ )
102
+ ] })
103
+ ]
104
+ }
105
+ );
106
+ };
107
+ export {
108
+ I as NodeContextMenu
109
+ };
110
+ //# sourceMappingURL=NodeContextMenu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeContextMenu.mjs","sources":["../../components/NodeContextMenu.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport { Edit2, Trash2, Settings, Copy, X } from 'lucide-react';\n\ninterface NodeContextMenuProps {\n x: number;\n y: number;\n nodeId: string;\n nodeLabel: string;\n onRename: () => void;\n onDelete: () => void;\n onConfigure: () => void;\n onDuplicate: () => void;\n onClose: () => void;\n}\n\nexport const NodeContextMenu: React.FC<NodeContextMenuProps> = ({\n x,\n y,\n nodeId: _nodeId,\n nodeLabel,\n onRename,\n onDelete,\n onConfigure,\n onDuplicate,\n onClose,\n}) => {\n const menuRef = useRef<HTMLDivElement>(null);\n\n // Close menu when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n onClose();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n // Add listeners after a short delay to avoid immediate closure\n const timeoutId = setTimeout(() => {\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape);\n }, 10);\n\n return () => {\n clearTimeout(timeoutId);\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n };\n }, [onClose]);\n\n // Prevent context menu from appearing on right-click within the menu\n const handleContextMenu = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n const handleAction = (action: () => void) => {\n action();\n onClose();\n };\n\n return (\n <div\n ref={menuRef}\n className=\"fixed z-50 bg-[#1e1e32] border border-gray-700 rounded-lg shadow-xl py-1 min-w-[180px]\"\n style={{\n left: `${x}px`,\n top: `${y}px`,\n }}\n onContextMenu={handleContextMenu}\n >\n {/* Header */}\n <div className=\"px-3 py-2 border-b border-gray-700/50 flex items-center justify-between\">\n <span className=\"text-xs font-medium text-gray-300 truncate max-w-[140px]\" title={nodeLabel}>\n {nodeLabel}\n </span>\n <button\n onClick={onClose}\n className=\"p-0.5 text-gray-500 hover:text-gray-300 rounded transition-colors\"\n title=\"Close\"\n >\n <X className=\"w-3 h-3\" />\n </button>\n </div>\n\n {/* Menu Items */}\n <div className=\"py-1\">\n <button\n onClick={() => handleAction(onRename)}\n className=\"w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-800/50 flex items-center gap-2 transition-colors\"\n >\n <Edit2 className=\"w-4 h-4\" />\n <span>Rename</span>\n </button>\n\n <button\n onClick={() => handleAction(onConfigure)}\n className=\"w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-800/50 flex items-center gap-2 transition-colors\"\n >\n <Settings className=\"w-4 h-4\" />\n <span>Configure</span>\n </button>\n\n <button\n onClick={() => handleAction(onDuplicate)}\n className=\"w-full px-3 py-2 text-left text-sm text-gray-300 hover:bg-gray-800/50 flex items-center gap-2 transition-colors\"\n >\n <Copy className=\"w-4 h-4\" />\n <span>Duplicate</span>\n </button>\n\n <div className=\"my-1 border-t border-gray-700/50\" />\n\n <button\n onClick={() => handleAction(onDelete)}\n className=\"w-full px-3 py-2 text-left text-sm text-red-400 hover:bg-red-500/10 flex items-center gap-2 transition-colors\"\n >\n <Trash2 className=\"w-4 h-4\" />\n <span>Delete</span>\n </button>\n </div>\n </div>\n );\n};\n"],"names":["NodeContextMenu","x","y","_nodeId","nodeLabel","onRename","onDelete","onConfigure","onDuplicate","onClose","menuRef","useRef","useEffect","handleClickOutside","event","handleEscape","timeoutId","handleContextMenu","e","handleAction","action","jsxs","jsx","X","Edit2","Settings","Copy","Trash2"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import 'reactflow/dist/style.css';
3
+ export declare const PipelineCanvas: React.FC;
4
+ //# sourceMappingURL=PipelineCanvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PipelineCanvas.d.ts","sourceRoot":"","sources":["../../components/PipelineCanvas.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAejF,OAAO,0BAA0B,CAAC;AAwqBlC,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAw6BlC,CAAC"}