@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.
- package/LICENSE +21 -0
- package/README.md +545 -0
- package/dist/_virtual/dynamic-import-helper.mjs +17 -0
- package/dist/_virtual/dynamic-import-helper.mjs.map +1 -0
- package/dist/components/CustomHandle.d.ts +9 -0
- package/dist/components/CustomHandle.d.ts.map +1 -0
- package/dist/components/CustomHandle.mjs +18 -0
- package/dist/components/CustomHandle.mjs.map +1 -0
- package/dist/components/ExecutionLogsPanel.d.ts +3 -0
- package/dist/components/ExecutionLogsPanel.d.ts.map +1 -0
- package/dist/components/ExecutionLogsPanel.mjs +189 -0
- package/dist/components/ExecutionLogsPanel.mjs.map +1 -0
- package/dist/components/NodeContextMenu.d.ts +15 -0
- package/dist/components/NodeContextMenu.d.ts.map +1 -0
- package/dist/components/NodeContextMenu.mjs +110 -0
- package/dist/components/NodeContextMenu.mjs.map +1 -0
- package/dist/components/PipelineCanvas.d.ts +4 -0
- package/dist/components/PipelineCanvas.d.ts.map +1 -0
- package/dist/components/PipelineCanvas.mjs +1016 -0
- package/dist/components/PipelineCanvas.mjs.map +1 -0
- package/dist/components/PipelineCanvasProvider.d.ts +30 -0
- package/dist/components/PipelineCanvasProvider.d.ts.map +1 -0
- package/dist/components/PipelineCanvasProvider.mjs +7 -0
- package/dist/components/PipelineCanvasProvider.mjs.map +1 -0
- package/dist/components/PipelineExecution.d.ts +16 -0
- package/dist/components/PipelineExecution.d.ts.map +1 -0
- package/dist/components/PipelineExecution.mjs +310 -0
- package/dist/components/PipelineExecution.mjs.map +1 -0
- package/dist/components/PipelineManager.d.ts +8 -0
- package/dist/components/PipelineManager.d.ts.map +1 -0
- package/dist/components/PipelineManager.mjs +143 -0
- package/dist/components/PipelineManager.mjs.map +1 -0
- package/dist/components/PipelineNodeConfig.d.ts +11 -0
- package/dist/components/PipelineNodeConfig.d.ts.map +1 -0
- package/dist/components/PipelineNodeConfig.mjs +1808 -0
- package/dist/components/PipelineNodeConfig.mjs.map +1 -0
- package/dist/components/PipelineNodePalette.d.ts +3 -0
- package/dist/components/PipelineNodePalette.d.ts.map +1 -0
- package/dist/components/PipelineNodePalette.mjs +87 -0
- package/dist/components/PipelineNodePalette.mjs.map +1 -0
- package/dist/components/SavePipelineDialog.d.ts +9 -0
- package/dist/components/SavePipelineDialog.d.ts.map +1 -0
- package/dist/components/SavePipelineDialog.mjs +140 -0
- package/dist/components/SavePipelineDialog.mjs.map +1 -0
- package/dist/components/SavedPipelinesList.d.ts +3 -0
- package/dist/components/SavedPipelinesList.d.ts.map +1 -0
- package/dist/components/SavedPipelinesList.mjs +172 -0
- package/dist/components/SavedPipelinesList.mjs.map +1 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/alert.d.ts +9 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/alert.mjs +51 -0
- package/dist/components/ui/alert.mjs.map +1 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.mjs +45 -0
- package/dist/components/ui/button.mjs.map +1 -0
- package/dist/components/ui/dialog.d.ts +20 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.mjs +99 -0
- package/dist/components/ui/dialog.mjs.map +1 -0
- package/dist/components/ui/index.d.ts +8 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/input.d.ts +6 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.mjs +22 -0
- package/dist/components/ui/input.mjs.map +1 -0
- package/dist/components/ui/label.d.ts +6 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.mjs +20 -0
- package/dist/components/ui/label.mjs.map +1 -0
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.mjs +121 -0
- package/dist/components/ui/select.mjs.map +1 -0
- package/dist/components/ui/tooltip.d.ts +8 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.mjs +24 -0
- package/dist/components/ui/tooltip.mjs.map +1 -0
- package/dist/context/PipelineContext.d.ts +50 -0
- package/dist/context/PipelineContext.d.ts.map +1 -0
- package/dist/context/PipelineContext.mjs +36 -0
- package/dist/context/PipelineContext.mjs.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +45 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.mjs +9 -0
- package/dist/lib/utils.mjs.map +1 -0
- package/dist/node_modules/zustand/esm/middleware.mjs +256 -0
- package/dist/node_modules/zustand/esm/middleware.mjs.map +1 -0
- package/dist/nodes/alphafold_node/node.json.mjs +82 -0
- package/dist/nodes/alphafold_node/node.json.mjs.map +1 -0
- package/dist/nodes/http_request_node/node.json.mjs +383 -0
- package/dist/nodes/http_request_node/node.json.mjs.map +1 -0
- package/dist/nodes/input_node/node.json.mjs +51 -0
- package/dist/nodes/input_node/node.json.mjs.map +1 -0
- package/dist/nodes/message_input_node/node.json.mjs +90 -0
- package/dist/nodes/message_input_node/node.json.mjs.map +1 -0
- package/dist/nodes/proteinmpnn_node/node.json.mjs +83 -0
- package/dist/nodes/proteinmpnn_node/node.json.mjs.map +1 -0
- package/dist/nodes/rfdiffusion_node/node.json.mjs +281 -0
- package/dist/nodes/rfdiffusion_node/node.json.mjs.map +1 -0
- package/dist/store/pipelineStore.d.ts +108 -0
- package/dist/store/pipelineStore.d.ts.map +1 -0
- package/dist/store/pipelineStore.mjs +633 -0
- package/dist/store/pipelineStore.mjs.map +1 -0
- package/dist/style.css +1 -0
- package/dist/types/dependencies.d.ts +93 -0
- package/dist/types/dependencies.d.ts.map +1 -0
- package/dist/types/index.d.ts +56 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/logger.d.ts +67 -0
- package/dist/types/logger.d.ts.map +1 -0
- package/dist/types/logger.mjs +22 -0
- package/dist/types/logger.mjs.map +1 -0
- package/dist/utils/executionEngine.d.ts +27 -0
- package/dist/utils/executionEngine.d.ts.map +1 -0
- package/dist/utils/executionEngine.mjs +461 -0
- package/dist/utils/executionEngine.mjs.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +23 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.mjs +29 -0
- package/dist/utils/logger.mjs.map +1 -0
- package/dist/utils/nodeLoader.d.ts +76 -0
- package/dist/utils/nodeLoader.d.ts.map +1 -0
- package/dist/utils/nodeLoader.mjs +48 -0
- package/dist/utils/nodeLoader.mjs.map +1 -0
- package/dist/utils/templateResolver.d.ts +10 -0
- package/dist/utils/templateResolver.d.ts.map +1 -0
- package/dist/utils/templateResolver.mjs +64 -0
- package/dist/utils/templateResolver.mjs.map +1 -0
- package/dist/utils/topologicalSort.d.ts +10 -0
- package/dist/utils/topologicalSort.d.ts.map +1 -0
- package/dist/utils/topologicalSort.mjs +25 -0
- package/dist/utils/topologicalSort.mjs.map +1 -0
- package/nodes/alphafold_node/node.json +77 -0
- package/nodes/http_request_node/node.json +311 -0
- package/nodes/input_node/node.json +47 -0
- package/nodes/message_input_node/node.json +56 -0
- package/nodes/proteinmpnn_node/node.json +78 -0
- package/nodes/rfdiffusion_node/node.json +231 -0
- package/package.json +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 NovoProtein AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
# @novoprotein/pipeline-canvas
|
|
2
|
+
|
|
3
|
+
A React component library for building visual pipeline/workflow canvases using React Flow.
|
|
4
|
+
|
|
5
|
+
## Installation from Private GitHub Repo
|
|
6
|
+
|
|
7
|
+
### Using SSH (Recommended for Private Repos)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install git+ssh://git@github.com:santosrai/pipeline-canvas.git
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Using HTTPS with Personal Access Token
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install git+https://YOUR_TOKEN@github.com/santosrai/pipeline-canvas.git
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Using Specific Branch or Tag
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install git+ssh://git@github.com:santosrai/pipeline-canvas.git#main
|
|
23
|
+
npm install git+ssh://git@github.com:santosrai/pipeline-canvas.git#v1.0.0
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
1. Install dependencies:
|
|
29
|
+
```bash
|
|
30
|
+
npm install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
2. Build the library:
|
|
34
|
+
```bash
|
|
35
|
+
npm run build
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Peer Dependencies
|
|
39
|
+
|
|
40
|
+
Make sure you have these installed in your consuming project:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install react react-dom reactflow zustand lucide-react
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### shadcn/ui Components (Required)
|
|
47
|
+
|
|
48
|
+
This library uses shadcn/ui components. You need to install the required Radix UI packages and utilities:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-select @radix-ui/react-slot @radix-ui/react-tooltip class-variance-authority clsx tailwind-merge
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Note**: The library includes shadcn component implementations in `components/ui/`, but you must install the peer dependencies above for them to work.
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### Basic Example (Standalone - No Dependencies)
|
|
59
|
+
|
|
60
|
+
The library works completely standalone without any dependencies:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { PipelineCanvas, PipelineCanvasProvider } from '@novoprotein/pipeline-canvas';
|
|
64
|
+
import '@novoprotein/pipeline-canvas/style.css';
|
|
65
|
+
|
|
66
|
+
function App() {
|
|
67
|
+
return (
|
|
68
|
+
<PipelineCanvasProvider>
|
|
69
|
+
<div style={{ width: '100vw', height: '100vh' }}>
|
|
70
|
+
<PipelineCanvas />
|
|
71
|
+
</div>
|
|
72
|
+
</PipelineCanvasProvider>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Note**: Without dependencies, the library works in "offline mode":
|
|
78
|
+
- Pipelines are saved locally (localStorage)
|
|
79
|
+
- No backend sync
|
|
80
|
+
- No authentication required
|
|
81
|
+
- File uploads work if your API supports unauthenticated requests
|
|
82
|
+
|
|
83
|
+
### With Authentication and API Client
|
|
84
|
+
|
|
85
|
+
For full functionality (backend sync, authenticated operations):
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import {
|
|
89
|
+
PipelineCanvas,
|
|
90
|
+
PipelineCanvasProvider,
|
|
91
|
+
type ApiClient,
|
|
92
|
+
type AuthState
|
|
93
|
+
} from '@novoprotein/pipeline-canvas';
|
|
94
|
+
import '@novoprotein/pipeline-canvas/style.css';
|
|
95
|
+
|
|
96
|
+
function App() {
|
|
97
|
+
// Your API client (compatible with axios, fetch, or custom)
|
|
98
|
+
const apiClient: ApiClient = {
|
|
99
|
+
get: async (url: string) => {
|
|
100
|
+
const response = await fetch(`/api${url}`, {
|
|
101
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
102
|
+
});
|
|
103
|
+
return { data: await response.json() };
|
|
104
|
+
},
|
|
105
|
+
post: async (url: string, data: any) => {
|
|
106
|
+
const response = await fetch(`/api${url}`, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: {
|
|
109
|
+
'Content-Type': 'application/json',
|
|
110
|
+
'Authorization': `Bearer ${token}`
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify(data)
|
|
113
|
+
});
|
|
114
|
+
return { data: await response.json() };
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Your auth state
|
|
119
|
+
const authState: AuthState = {
|
|
120
|
+
user: { id: 'user-123', email: 'user@example.com' },
|
|
121
|
+
isAuthenticated: true,
|
|
122
|
+
accessToken: token,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Session ID for execution context
|
|
126
|
+
const sessionId = 'session-456';
|
|
127
|
+
|
|
128
|
+
// Auth headers function for file uploads
|
|
129
|
+
const getAuthHeaders = () => ({
|
|
130
|
+
'Authorization': `Bearer ${token}`
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<PipelineCanvasProvider
|
|
135
|
+
apiClient={apiClient}
|
|
136
|
+
authState={authState}
|
|
137
|
+
sessionId={sessionId}
|
|
138
|
+
getAuthHeaders={getAuthHeaders}
|
|
139
|
+
>
|
|
140
|
+
<div style={{ width: '100vw', height: '100vh' }}>
|
|
141
|
+
<PipelineCanvas />
|
|
142
|
+
</div>
|
|
143
|
+
</PipelineCanvasProvider>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### With Axios API Client
|
|
149
|
+
|
|
150
|
+
If you're using axios:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import axios from 'axios';
|
|
154
|
+
import { PipelineCanvasProvider, type ApiClient } from '@novoprotein/pipeline-canvas';
|
|
155
|
+
|
|
156
|
+
const apiClient: ApiClient = {
|
|
157
|
+
get: (url: string, config?) => axios.get(url, config),
|
|
158
|
+
post: (url: string, data?: any, config?) => axios.post(url, data, config),
|
|
159
|
+
put: (url: string, data?: any, config?) => axios.put(url, data, config),
|
|
160
|
+
patch: (url: string, data?: any, config?) => axios.patch(url, data, config),
|
|
161
|
+
delete: (url: string, config?) => axios.delete(url, config),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
function App() {
|
|
165
|
+
return (
|
|
166
|
+
<PipelineCanvasProvider apiClient={apiClient}>
|
|
167
|
+
<PipelineCanvas />
|
|
168
|
+
</PipelineCanvasProvider>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Partial Dependencies
|
|
174
|
+
|
|
175
|
+
You can provide only the dependencies you need:
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
// Only API client (no auth)
|
|
179
|
+
<PipelineCanvasProvider apiClient={myApiClient}>
|
|
180
|
+
<PipelineCanvas />
|
|
181
|
+
</PipelineCanvasProvider>
|
|
182
|
+
|
|
183
|
+
// Only auth state (local operations only)
|
|
184
|
+
<PipelineCanvasProvider authState={authState}>
|
|
185
|
+
<PipelineCanvas />
|
|
186
|
+
</PipelineCanvasProvider>
|
|
187
|
+
|
|
188
|
+
// Everything optional - works standalone
|
|
189
|
+
<PipelineCanvasProvider>
|
|
190
|
+
<PipelineCanvas />
|
|
191
|
+
</PipelineCanvasProvider>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Using the Store
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { usePipelineStore } from '@novoprotein/pipeline-canvas';
|
|
198
|
+
|
|
199
|
+
function MyComponent() {
|
|
200
|
+
const { nodes, edges, addNode } = usePipelineStore();
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div>
|
|
204
|
+
<p>Nodes: {nodes.length}</p>
|
|
205
|
+
<button onClick={() => addNode({ id: '1', type: 'input', data: {} })}>
|
|
206
|
+
Add Node
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Using Context Directly
|
|
214
|
+
|
|
215
|
+
You can also access dependencies directly from context:
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
import { usePipelineContext } from '@novoprotein/pipeline-canvas';
|
|
219
|
+
|
|
220
|
+
function MyComponent() {
|
|
221
|
+
const { apiClient, authState, sessionId, getAuthHeaders } = usePipelineContext();
|
|
222
|
+
|
|
223
|
+
// Use dependencies as needed
|
|
224
|
+
if (authState?.user) {
|
|
225
|
+
// User is authenticated
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return <div>...</div>;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Dependency Injection
|
|
233
|
+
|
|
234
|
+
The library uses dependency injection to remain standalone and flexible. All dependencies are **optional**:
|
|
235
|
+
|
|
236
|
+
- **`apiClient`**: For backend operations (save, load, sync pipelines)
|
|
237
|
+
- **`authState`**: For user-specific features and authentication
|
|
238
|
+
- **`sessionId`**: For execution context and session tracking
|
|
239
|
+
- **`getAuthHeaders`**: For authenticated file uploads
|
|
240
|
+
- **`logger`**: For structured logging (optional, uses console by default)
|
|
241
|
+
- **`errorReporter`**: For error tracking (Sentry, LogRocket, etc.)
|
|
242
|
+
|
|
243
|
+
### Graceful Degradation
|
|
244
|
+
|
|
245
|
+
When dependencies are not provided:
|
|
246
|
+
- ✅ Pipelines work locally (localStorage)
|
|
247
|
+
- ✅ All UI features work
|
|
248
|
+
- ✅ Pipeline execution works (with provided apiClient or external APIs)
|
|
249
|
+
- ⚠️ Backend sync is skipped
|
|
250
|
+
- ⚠️ User-specific features are disabled
|
|
251
|
+
- ⚠️ File uploads may fail if API requires authentication
|
|
252
|
+
|
|
253
|
+
### Integration Examples
|
|
254
|
+
|
|
255
|
+
#### With Zustand Auth Store
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
import { useAuthStore } from './stores/authStore';
|
|
259
|
+
import { PipelineCanvasProvider } from '@novoprotein/pipeline-canvas';
|
|
260
|
+
|
|
261
|
+
function App() {
|
|
262
|
+
const user = useAuthStore(state => state.user);
|
|
263
|
+
const token = useAuthStore(state => state.accessToken);
|
|
264
|
+
|
|
265
|
+
const authState = {
|
|
266
|
+
user,
|
|
267
|
+
isAuthenticated: !!user,
|
|
268
|
+
accessToken: token,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<PipelineCanvasProvider authState={authState}>
|
|
273
|
+
<PipelineCanvas />
|
|
274
|
+
</PipelineCanvasProvider>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### With React Context Auth
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
import { useContext } from 'react';
|
|
283
|
+
import { AuthContext } from './AuthContext';
|
|
284
|
+
import { PipelineCanvasProvider } from '@novoprotein/pipeline-canvas';
|
|
285
|
+
|
|
286
|
+
function App() {
|
|
287
|
+
const { user, token } = useContext(AuthContext);
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<PipelineCanvasProvider
|
|
291
|
+
authState={{ user, isAuthenticated: !!user, accessToken: token }}
|
|
292
|
+
>
|
|
293
|
+
<PipelineCanvas />
|
|
294
|
+
</PipelineCanvasProvider>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Logging and Error Tracking
|
|
300
|
+
|
|
301
|
+
The library supports structured logging and error tracking through dependency injection. This allows you to integrate with your own logging systems (Sentry, LogRocket, Bugsnag, etc.) or use the default console logger.
|
|
302
|
+
|
|
303
|
+
### Basic Usage (Default Logger)
|
|
304
|
+
|
|
305
|
+
By default, the library uses a console logger that only logs in development mode:
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
import { PipelineCanvasProvider } from '@novoprotein/pipeline-canvas';
|
|
309
|
+
|
|
310
|
+
// No logger needed - uses default console logger (development only)
|
|
311
|
+
<PipelineCanvasProvider>
|
|
312
|
+
<PipelineCanvas />
|
|
313
|
+
</PipelineCanvasProvider>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Custom Logger
|
|
317
|
+
|
|
318
|
+
Provide your own logger for structured logging:
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import {
|
|
322
|
+
PipelineCanvasProvider,
|
|
323
|
+
type Logger
|
|
324
|
+
} from '@novoprotein/pipeline-canvas';
|
|
325
|
+
|
|
326
|
+
const myLogger: Logger = {
|
|
327
|
+
debug: (message, data) => {
|
|
328
|
+
// Your debug logging logic
|
|
329
|
+
console.debug(`[Pipeline] ${message}`, data);
|
|
330
|
+
},
|
|
331
|
+
info: (message, data) => {
|
|
332
|
+
// Your info logging logic
|
|
333
|
+
console.info(`[Pipeline] ${message}`, data);
|
|
334
|
+
},
|
|
335
|
+
warn: (message, data) => {
|
|
336
|
+
// Your warning logging logic
|
|
337
|
+
console.warn(`[Pipeline] ${message}`, data);
|
|
338
|
+
},
|
|
339
|
+
error: (message, error, data) => {
|
|
340
|
+
// Your error logging logic
|
|
341
|
+
console.error(`[Pipeline] ${message}`, error, data);
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
<PipelineCanvasProvider logger={myLogger}>
|
|
346
|
+
<PipelineCanvas />
|
|
347
|
+
</PipelineCanvasProvider>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Error Tracking (Sentry Example)
|
|
351
|
+
|
|
352
|
+
Integrate with error tracking services:
|
|
353
|
+
|
|
354
|
+
```tsx
|
|
355
|
+
import * as Sentry from '@sentry/react';
|
|
356
|
+
import {
|
|
357
|
+
PipelineCanvasProvider,
|
|
358
|
+
type ErrorReporter
|
|
359
|
+
} from '@novoprotein/pipeline-canvas';
|
|
360
|
+
|
|
361
|
+
const errorReporter: ErrorReporter = {
|
|
362
|
+
captureException: (error, context) => {
|
|
363
|
+
Sentry.captureException(error, {
|
|
364
|
+
extra: context,
|
|
365
|
+
tags: {
|
|
366
|
+
component: 'pipeline-canvas',
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
},
|
|
370
|
+
captureMessage: (message, level, context) => {
|
|
371
|
+
Sentry.captureMessage(message, {
|
|
372
|
+
level: level === 'error' ? 'error' : level === 'warning' ? 'warning' : 'info',
|
|
373
|
+
extra: context,
|
|
374
|
+
tags: {
|
|
375
|
+
component: 'pipeline-canvas',
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
},
|
|
379
|
+
setUser: (user) => {
|
|
380
|
+
Sentry.setUser({
|
|
381
|
+
id: user.id,
|
|
382
|
+
email: user.email,
|
|
383
|
+
});
|
|
384
|
+
},
|
|
385
|
+
setContext: (key, context) => {
|
|
386
|
+
Sentry.setContext(key, context);
|
|
387
|
+
},
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
<PipelineCanvasProvider errorReporter={errorReporter}>
|
|
391
|
+
<PipelineCanvas />
|
|
392
|
+
</PipelineCanvasProvider>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### LogRocket Example
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
import LogRocket from 'logrocket';
|
|
399
|
+
import { PipelineCanvasProvider, type ErrorReporter } from '@novoprotein/pipeline-canvas';
|
|
400
|
+
|
|
401
|
+
const errorReporter: ErrorReporter = {
|
|
402
|
+
captureException: (error, context) => {
|
|
403
|
+
LogRocket.captureException(error, {
|
|
404
|
+
extra: context,
|
|
405
|
+
});
|
|
406
|
+
},
|
|
407
|
+
captureMessage: (message, level, context) => {
|
|
408
|
+
LogRocket.captureMessage(message, {
|
|
409
|
+
level,
|
|
410
|
+
extra: context,
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
setUser: (user) => {
|
|
414
|
+
LogRocket.identify(user.id, {
|
|
415
|
+
email: user.email,
|
|
416
|
+
});
|
|
417
|
+
},
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
<PipelineCanvasProvider errorReporter={errorReporter}>
|
|
421
|
+
<PipelineCanvas />
|
|
422
|
+
</PipelineCanvasProvider>
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Using Logger in Your Code
|
|
426
|
+
|
|
427
|
+
You can access the logger from context:
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
import { usePipelineContext } from '@novoprotein/pipeline-canvas';
|
|
431
|
+
|
|
432
|
+
function MyComponent() {
|
|
433
|
+
const { logger } = usePipelineContext();
|
|
434
|
+
|
|
435
|
+
const handleAction = () => {
|
|
436
|
+
logger?.info('Action performed', { action: 'click' });
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
return <button onClick={handleAction}>Click me</button>;
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### What Gets Logged
|
|
444
|
+
|
|
445
|
+
The library logs:
|
|
446
|
+
- **Pipeline execution events**: Start, completion, errors
|
|
447
|
+
- **Node execution**: Status changes, errors, results
|
|
448
|
+
- **API requests**: Request/response details (if enabled)
|
|
449
|
+
- **User actions**: Pipeline save, load, delete operations
|
|
450
|
+
- **Errors**: All errors with full context (node ID, pipeline ID, error details)
|
|
451
|
+
|
|
452
|
+
### Privacy and Security
|
|
453
|
+
|
|
454
|
+
- **No automatic data collection**: Logging is opt-in via dependency injection
|
|
455
|
+
- **You control what gets logged**: Provide your own logger/error reporter
|
|
456
|
+
- **No external calls**: Default logger only uses console (no network requests)
|
|
457
|
+
- **Context-aware**: All logs include relevant context (pipeline ID, node ID, etc.)
|
|
458
|
+
|
|
459
|
+
### Styling
|
|
460
|
+
|
|
461
|
+
The library uses Tailwind CSS classes and shadcn/ui CSS variables. Make sure Tailwind is configured in your project:
|
|
462
|
+
|
|
463
|
+
```js
|
|
464
|
+
// tailwind.config.js
|
|
465
|
+
module.exports = {
|
|
466
|
+
content: [
|
|
467
|
+
'./src/**/*.{js,jsx,ts,tsx}',
|
|
468
|
+
'./node_modules/@novoprotein/pipeline-canvas/**/*.{js,jsx,ts,tsx}',
|
|
469
|
+
],
|
|
470
|
+
theme: {
|
|
471
|
+
extend: {
|
|
472
|
+
// shadcn/ui theme variables are included in the library's style.css
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
// ... rest of config
|
|
476
|
+
};
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Also import the CSS file in your main entry:
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
// main.tsx or App.tsx
|
|
483
|
+
import '@novoprotein/pipeline-canvas/style.css';
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
The library includes shadcn/ui CSS variables for theming. The components support both light and dark themes via CSS variables.
|
|
487
|
+
|
|
488
|
+
## Development
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
# Type check
|
|
492
|
+
npm run type-check
|
|
493
|
+
|
|
494
|
+
# Build
|
|
495
|
+
npm run build
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Creating New Node Types
|
|
499
|
+
|
|
500
|
+
When creating a new node type, **please read the [Node Development Guide](../../docs/node-development-guide.md)** first. It covers critical best practices and common pitfalls, including:
|
|
501
|
+
|
|
502
|
+
- ✅ Always initialize nodes with default config
|
|
503
|
+
- ✅ Keep execution logs accessible after completion
|
|
504
|
+
- ✅ Don't force navigation during execution
|
|
505
|
+
- ✅ Handle multiple data structures in output extraction
|
|
506
|
+
- ✅ Common pitfalls and how to avoid them
|
|
507
|
+
|
|
508
|
+
This guide will save you time and prevent common issues!
|
|
509
|
+
|
|
510
|
+
## Project Structure
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
pipeline-canvas/
|
|
514
|
+
├── components/ # React components
|
|
515
|
+
│ ├── PipelineCanvas.tsx
|
|
516
|
+
│ ├── PipelineNodeConfig.tsx
|
|
517
|
+
│ ├── PipelineNodePalette.tsx
|
|
518
|
+
│ ├── PipelineExecution.tsx
|
|
519
|
+
│ ├── PipelineManager.tsx
|
|
520
|
+
│ ├── CustomHandle.tsx
|
|
521
|
+
│ └── ExecutionLogsPanel.tsx
|
|
522
|
+
├── nodes/ # Node type configurations (JSON)
|
|
523
|
+
│ ├── input_node/
|
|
524
|
+
│ ├── rfdiffusion_node/
|
|
525
|
+
│ ├── proteinmpnn_node/
|
|
526
|
+
│ └── alphafold_node/
|
|
527
|
+
├── store/ # Zustand store
|
|
528
|
+
│ └── pipelineStore.ts
|
|
529
|
+
├── types/ # TypeScript types
|
|
530
|
+
│ └── index.ts
|
|
531
|
+
├── utils/ # Utility functions
|
|
532
|
+
│ ├── topologicalSort.ts
|
|
533
|
+
│ └── nodeLoader.ts
|
|
534
|
+
├── dist/ # Build output (generated)
|
|
535
|
+
├── index.ts # Main export file
|
|
536
|
+
├── style.css # CSS styles
|
|
537
|
+
├── package.json
|
|
538
|
+
├── tsconfig.json
|
|
539
|
+
└── vite.config.ts
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## License
|
|
543
|
+
|
|
544
|
+
MIT
|
|
545
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const l = (r, n, t) => {
|
|
2
|
+
const e = r[n];
|
|
3
|
+
return e ? typeof e == "function" ? e() : Promise.resolve(e) : new Promise((i, o) => {
|
|
4
|
+
(typeof queueMicrotask == "function" ? queueMicrotask : setTimeout)(
|
|
5
|
+
o.bind(
|
|
6
|
+
null,
|
|
7
|
+
new Error(
|
|
8
|
+
"Unknown variable dynamic import: " + n + (n.split("/").length !== t ? ". Note that variables only represent file names one level deep." : "")
|
|
9
|
+
)
|
|
10
|
+
)
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
l as default
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=dynamic-import-helper.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic-import-helper.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Position } from 'reactflow';
|
|
3
|
+
interface CustomHandleProps {
|
|
4
|
+
type: 'source' | 'target';
|
|
5
|
+
position: Position;
|
|
6
|
+
}
|
|
7
|
+
export declare const CustomHandle: React.FC<CustomHandleProps>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=CustomHandle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomHandle.d.ts","sourceRoot":"","sources":["../../components/CustomHandle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAU,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE7C,UAAU,iBAAiB;IACzB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAUpD,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
2
|
+
import { Position as r, Handle as m } from "reactflow";
|
|
3
|
+
const a = ({ type: e, position: t }) => {
|
|
4
|
+
const o = t === r.Left;
|
|
5
|
+
return /* @__PURE__ */ s(
|
|
6
|
+
m,
|
|
7
|
+
{
|
|
8
|
+
type: e,
|
|
9
|
+
position: t,
|
|
10
|
+
className: "custom-handle",
|
|
11
|
+
style: o ? { left: -6 } : { right: -6 }
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
a as CustomHandle
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=CustomHandle.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomHandle.mjs","sources":["../../components/CustomHandle.tsx"],"sourcesContent":["import React from 'react';\nimport { Handle, Position } from 'reactflow';\n\ninterface CustomHandleProps {\n type: 'source' | 'target';\n position: Position;\n}\n\nexport const CustomHandle: React.FC<CustomHandleProps> = ({ type, position }) => {\n const isLeft = position === Position.Left;\n return (\n <Handle\n type={type}\n position={position}\n className=\"custom-handle\"\n style={isLeft ? { left: -6 } : { right: -6 }}\n />\n );\n};\n\n\n\n\n\n"],"names":["CustomHandle","type","position","isLeft","Position","jsx","Handle"],"mappings":";;AAQO,MAAMA,IAA4C,CAAC,EAAE,MAAAC,GAAM,UAAAC,QAAe;AAC/E,QAAMC,IAASD,MAAaE,EAAS;AACrC,SACE,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,MAAAL;AAAA,MACA,UAAAC;AAAA,MACA,WAAU;AAAA,MACV,OAAOC,IAAS,EAAE,MAAM,OAAO,EAAE,OAAO,GAAA;AAAA,IAAG;AAAA,EAAA;AAGjD;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecutionLogsPanel.d.ts","sourceRoot":"","sources":["../../components/ExecutionLogsPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AA8N1B,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAoItC,CAAC"}
|