@linkdlab/funcnodes_react_flow 0.1.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 (67) hide show
  1. package/README.md +46 -0
  2. package/package copy.json +63 -0
  3. package/package.json +75 -0
  4. package/public/favicon.ico +0 -0
  5. package/public/index.html +43 -0
  6. package/public/logo192.png +0 -0
  7. package/public/logo512.png +0 -0
  8. package/public/manifest.json +25 -0
  9. package/public/robots.txt +3 -0
  10. package/public/worker_manager +1 -0
  11. package/src/App.css +38 -0
  12. package/src/App.test.tsx +9 -0
  13. package/src/App.tsx +22 -0
  14. package/src/frontend/datarenderer/images.tsx +28 -0
  15. package/src/frontend/datarenderer/index.tsx +53 -0
  16. package/src/frontend/datarenderer/plotly.tsx +82 -0
  17. package/src/frontend/dialog.scss +88 -0
  18. package/src/frontend/dialog.tsx +70 -0
  19. package/src/frontend/edge.scss +15 -0
  20. package/src/frontend/edge.tsx +31 -0
  21. package/src/frontend/funcnodesreactflow.scss +63 -0
  22. package/src/frontend/funcnodesreactflow.tsx +283 -0
  23. package/src/frontend/header/header.scss +48 -0
  24. package/src/frontend/header/index.tsx +268 -0
  25. package/src/frontend/index.tsx +4 -0
  26. package/src/frontend/layout/htmlelements.scss +63 -0
  27. package/src/frontend/lib.scss +157 -0
  28. package/src/frontend/lib.tsx +198 -0
  29. package/src/frontend/node/index.tsx +3 -0
  30. package/src/frontend/node/io/default_input_renderer.tsx +327 -0
  31. package/src/frontend/node/io/default_output_render.tsx +26 -0
  32. package/src/frontend/node/io/handle_renderer.tsx +89 -0
  33. package/src/frontend/node/io/index.tsx +4 -0
  34. package/src/frontend/node/io/io.scss +91 -0
  35. package/src/frontend/node/io/io.tsx +114 -0
  36. package/src/frontend/node/io/nodeinput.tsx +125 -0
  37. package/src/frontend/node/io/nodeoutput.tsx +37 -0
  38. package/src/frontend/node/node.scss +265 -0
  39. package/src/frontend/node/node.tsx +208 -0
  40. package/src/frontend/nodecontextmenu.scss +18 -0
  41. package/src/frontend/utils/colorpicker.scss +37 -0
  42. package/src/frontend/utils/colorpicker.tsx +342 -0
  43. package/src/frontend/utils/jsondata.tsx +19 -0
  44. package/src/frontend/utils/table.scss +22 -0
  45. package/src/frontend/utils/table.tsx +159 -0
  46. package/src/funcnodes/funcnodesworker.ts +455 -0
  47. package/src/funcnodes/index.ts +4 -0
  48. package/src/funcnodes/websocketworker.ts +153 -0
  49. package/src/funcnodes/workermanager.ts +229 -0
  50. package/src/index.css +13 -0
  51. package/src/index.tsx +19 -0
  52. package/src/logo.svg +1 -0
  53. package/src/react-app-env.d.ts +1 -0
  54. package/src/reportWebVitals.ts +15 -0
  55. package/src/setupTests.ts +5 -0
  56. package/src/state/edge.ts +35 -0
  57. package/src/state/fnrfzst.ts +440 -0
  58. package/src/state/index.ts +139 -0
  59. package/src/state/lib.ts +26 -0
  60. package/src/state/node.ts +118 -0
  61. package/src/state/nodespace.ts +151 -0
  62. package/src/state/reactflow.ts +65 -0
  63. package/src/types/lib.d.ts +16 -0
  64. package/src/types/node.d.ts +29 -0
  65. package/src/types/nodeio.d.ts +82 -0
  66. package/src/types/worker.d.ts +56 -0
  67. package/tsconfig.json +20 -0
@@ -0,0 +1,229 @@
1
+ import { FuncNodesReactFlowZustandInterface, WorkersState } from "../state";
2
+ import FuncNodesWorker from "./funcnodesworker";
3
+ import WebSocketWorker from "./websocketworker";
4
+
5
+ class WorkerManager {
6
+ private wsuri: string;
7
+ private workers: any;
8
+ private ws: WebSocket | null = null;
9
+ private reconnectAttempts: number = 0;
10
+ private maxReconnectAttempts: number = 999;
11
+ private initialTimeout: number = 200; // Initial reconnect delay in ms
12
+ private maxTimeout: number = 2000; // Maximum reconnect delay
13
+ private zustand: FuncNodesReactFlowZustandInterface;
14
+ private connectionTimeout?: NodeJS.Timeout;
15
+ on_setWorker: (worker: FuncNodesWorker | undefined) => void;
16
+ constructor(wsuri: string, zustand: FuncNodesReactFlowZustandInterface) {
17
+ this.wsuri = wsuri;
18
+ this.zustand = zustand;
19
+ this.workers = {};
20
+ this.on_setWorker = (worker: FuncNodesWorker | undefined) => {
21
+ console.log("WorkerManager: on_setWorker", worker);
22
+ this.zustand.worker = worker;
23
+ };
24
+ this.connect();
25
+ }
26
+ private connect(): void {
27
+ this.zustand.set_progress({
28
+ progress: 0,
29
+ message: "connecting to worker manager",
30
+ status: "info",
31
+ blocking: true,
32
+ });
33
+ console.log("Connecting to websocket");
34
+ this.ws = new WebSocket(this.wsuri);
35
+
36
+ this.ws.onopen = () => {
37
+ this.onopen();
38
+ };
39
+
40
+ this.ws.onclose = () => {
41
+ this.onclose();
42
+ };
43
+
44
+ this.ws.onerror = () => {
45
+ this.on_ws_error();
46
+ };
47
+
48
+ this.ws.onmessage = (event) => {
49
+ this.onmessage(event.data);
50
+ };
51
+
52
+ this.connectionTimeout = setTimeout(() => {
53
+ if (this.ws?.readyState !== WebSocket.OPEN) {
54
+ this.on_ws_error();
55
+ }
56
+ }, 5000);
57
+ }
58
+
59
+ on_ws_error() {
60
+ console.warn("Websocket error");
61
+ if (this.ws) {
62
+ this.ws.close(); // Ensure the connection is closed before attempting to reconnect
63
+ } else {
64
+ this.reconnect();
65
+ }
66
+ }
67
+
68
+ onopen() {
69
+ if (this.connectionTimeout) {
70
+ clearTimeout(this.connectionTimeout);
71
+ this.connectionTimeout = undefined;
72
+ }
73
+ this.zustand.auto_progress();
74
+ console.log("WorkerManager: onopen");
75
+ if (this.ws) {
76
+ this.ws.send("worker_status");
77
+ }
78
+
79
+ // Get active worker from window storage
80
+ const active_worker = window.localStorage.getItem(
81
+ "funcnodes__active_worker"
82
+ );
83
+ if (active_worker) {
84
+ this.set_active(active_worker);
85
+ }
86
+ }
87
+ onmessage(event: string) {
88
+ let msg = JSON.parse(event);
89
+ if (msg.type === "worker_status") {
90
+ console.debug("WorkerManager: worker_status", msg);
91
+ const new_state: WorkersState = {};
92
+ for (let worker of msg.active) {
93
+ worker.active = true;
94
+ new_state[worker.uuid] = worker;
95
+ }
96
+ for (let worker of msg.inactive) {
97
+ worker.active = false;
98
+ new_state[worker.uuid] = worker;
99
+ }
100
+ this.zustand.workers.setState(new_state);
101
+ return;
102
+ } else if (msg.type === "set_worker") {
103
+ if (msg.data.type === "WSWorker") {
104
+ let url =
105
+ "ws" +
106
+ (msg.data.ssl ? "s" : "") +
107
+ "://" +
108
+ msg.data.host +
109
+ ":" +
110
+ msg.data.port;
111
+ this.setWorker(
112
+ this.workers[msg.data.uuid] ||
113
+ new WebSocketWorker({
114
+ url,
115
+ zustand: this.zustand,
116
+ uuid: msg.data.uuid,
117
+ })
118
+ );
119
+ } else {
120
+ console.error("WorkerManager: unknown worker type", msg);
121
+ }
122
+
123
+ //store active worker in window storage
124
+
125
+ return;
126
+ } else if (msg.type === "progress") {
127
+ this.zustand.set_progress(msg as ProgressStateMessage);
128
+ return;
129
+ }
130
+ console.error("WorkerManager: unknown message", msg);
131
+ }
132
+
133
+ setWorker(worker: FuncNodesWorker | undefined) {
134
+ for (let w in this.workers) {
135
+ if (w !== worker?.uuid) {
136
+ this.workers[w].disconnect();
137
+ }
138
+ }
139
+ if (worker !== undefined) {
140
+ this.workers[worker.uuid] = worker;
141
+ worker.reconnect();
142
+ }
143
+ window.localStorage.setItem("funcnodes__active_worker", worker?.uuid || "");
144
+ if (this.zustand.worker !== undefined) {
145
+ this.zustand.clear_all();
146
+ }
147
+ this.zustand.worker = worker;
148
+ this.on_setWorker(worker);
149
+ }
150
+
151
+ async restart_worker(workerid: string) {
152
+ this.ws?.send(JSON.stringify({ type: "restart_worker", workerid }));
153
+ }
154
+
155
+ private calculateReconnectTimeout(): number {
156
+ // Increase timeout exponentially, capped at maxTimeout
157
+ let timeout = Math.min(
158
+ this.initialTimeout * Math.pow(2, this.reconnectAttempts),
159
+ this.maxTimeout
160
+ );
161
+ return timeout;
162
+ }
163
+
164
+ private reconnect(): void {
165
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
166
+ let timeout = this.calculateReconnectTimeout();
167
+ console.log(`Attempting to reconnect in ${timeout} ms`);
168
+
169
+ setTimeout(() => {
170
+ if (this.ws) {
171
+ if (this.ws.readyState === WebSocket.OPEN) {
172
+ return;
173
+ }
174
+ }
175
+ this.reconnectAttempts++;
176
+ this.connect();
177
+ }, timeout);
178
+ } else {
179
+ console.warn("Maximum reconnect attempts reached. Giving up.");
180
+ }
181
+ }
182
+
183
+ onclose() {
184
+ console.log("WorkerManager: onclose");
185
+ this.reconnect(); // Attempt to reconnect
186
+ }
187
+
188
+ set_active(workerid: string) {
189
+ if (!this.ws) return;
190
+ this.ws.send(JSON.stringify({ type: "set_active", workerid }));
191
+ }
192
+
193
+ new_worker({
194
+ name,
195
+ reference,
196
+ copyLib,
197
+ copyNS,
198
+ }: {
199
+ name?: string;
200
+ reference?: string;
201
+ copyLib?: boolean;
202
+ copyNS?: boolean;
203
+ }) {
204
+ if (!name) name = undefined;
205
+ if (!copyLib) copyLib = false;
206
+ if (!copyNS) copyNS = false;
207
+ if (!reference) {
208
+ reference = undefined;
209
+ copyLib = false;
210
+ copyNS = false;
211
+ }
212
+
213
+ if (this.ws) {
214
+ this.ws.send(
215
+ JSON.stringify({
216
+ type: "new_worker",
217
+ kwargs: {
218
+ name,
219
+ reference,
220
+ copyLib,
221
+ copyNS,
222
+ },
223
+ })
224
+ );
225
+ }
226
+ }
227
+ }
228
+
229
+ export default WorkerManager;
package/src/index.css ADDED
@@ -0,0 +1,13 @@
1
+ body {
2
+ margin: 0;
3
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5
+ sans-serif;
6
+ -webkit-font-smoothing: antialiased;
7
+ -moz-osx-font-smoothing: grayscale;
8
+ }
9
+
10
+ code {
11
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12
+ monospace;
13
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import './index.css';
4
+ import App from './App';
5
+ import reportWebVitals from './reportWebVitals';
6
+
7
+ const root = ReactDOM.createRoot(
8
+ document.getElementById('root') as HTMLElement
9
+ );
10
+ root.render(
11
+ <React.StrictMode>
12
+ <App />
13
+ </React.StrictMode>
14
+ );
15
+
16
+ // If you want to start measuring performance in your app, pass a function
17
+ // to log results (for example: reportWebVitals(console.log))
18
+ // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
19
+ reportWebVitals();
package/src/logo.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
@@ -0,0 +1 @@
1
+ /// <reference types="react-scripts" />
@@ -0,0 +1,15 @@
1
+ import { ReportHandler } from 'web-vitals';
2
+
3
+ const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4
+ if (onPerfEntry && onPerfEntry instanceof Function) {
5
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6
+ getCLS(onPerfEntry);
7
+ getFID(onPerfEntry);
8
+ getFCP(onPerfEntry);
9
+ getLCP(onPerfEntry);
10
+ getTTFB(onPerfEntry);
11
+ });
12
+ }
13
+ };
14
+
15
+ export default reportWebVitals;
@@ -0,0 +1,5 @@
1
+ // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
+ // allows you to do things like:
3
+ // expect(element).toHaveTextContent(/react/i)
4
+ // learn more: https://github.com/testing-library/jest-dom
5
+ import '@testing-library/jest-dom';
@@ -0,0 +1,35 @@
1
+ interface BaseEdgeAction {
2
+ type: string;
3
+ src_nid: string;
4
+ src_ioid: string;
5
+ trg_nid: string;
6
+ trg_ioid: string;
7
+ from_remote: boolean;
8
+ }
9
+
10
+ interface EdgeActionAdd extends BaseEdgeAction {
11
+ type: "add";
12
+ }
13
+
14
+ interface EdgeActionDelete extends BaseEdgeAction {
15
+ type: "delete";
16
+ }
17
+
18
+ type EdgeAction = EdgeActionAdd | EdgeActionDelete;
19
+
20
+ const generate_edge_id = ({
21
+ src_nid,
22
+ src_ioid,
23
+ trg_nid,
24
+ trg_ioid,
25
+ }: {
26
+ src_nid: string;
27
+ src_ioid: string;
28
+ trg_nid: string;
29
+ trg_ioid: string;
30
+ }) => {
31
+ return [`${src_nid}:${src_ioid}`, `${trg_nid}:${trg_ioid}`].sort().join("--");
32
+ };
33
+
34
+ export { generate_edge_id };
35
+ export type { EdgeAction, EdgeActionAdd, EdgeActionDelete };