@luxonis/depthai-pipeline-lib 1.5.0 → 1.7.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/dist/src/components/Node.js +24 -8
- package/dist/src/components/PipelineCanvas.d.ts +4 -1
- package/dist/src/components/PipelineCanvas.js +131 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +1 -0
- package/dist/src/services/pipeline-state.d.ts +42 -0
- package/dist/src/services/pipeline-state.js +13 -0
- package/dist/src/services/pipeline.d.ts +8 -1
- package/dist/src/services/pipeline.js +45 -2
- package/package.json +1 -1
- package/dist/src/styled-system/chunks/src__components__Node.css +0 -196
- package/dist/src/styled-system/chunks/src__components__PipelineCanvas.css +0 -26
- package/dist/src/styled-system/global.css +0 -70
- package/dist/src/styled-system/patterns/link-box.d.mts +0 -21
- package/dist/src/styled-system/patterns/link-box.mjs +0 -19
- package/dist/src/styled-system/recipes/create-recipe.d.mts +0 -1
- package/dist/src/styled-system/reset.css +0 -206
- package/dist/src/styled-system/static.css +0 -320
- package/dist/src/styled-system/tokens/index.css +0 -620
- package/dist/src/styled-system/tokens/keyframes.css +0 -56
- package/dist/src/styled-system/types/helpers.d.mts +0 -2
|
@@ -6,16 +6,20 @@ import { css } from '../styled-system/css/css.mjs';
|
|
|
6
6
|
import { DOCS_BASE_URL, NodesWithLinks, } from '../services/pipeline.js';
|
|
7
7
|
const NodeHandles = props => {
|
|
8
8
|
const { handles, type } = props;
|
|
9
|
-
return (_jsx(Flex, { full: true, direction: "column", align: type === 'input' ? 'start' : 'end', children: handles.map(({ type: handleType, id, blocking, queueSize, name }) => (_jsxs(Flex, { position: "relative", align: "end", direction: handleType === 'input' ? 'row' : 'row-reverse', children: [_jsx(Handle, { type: handleType === 'input' ? 'target' : 'source', position: handleType === 'input' ? Position.Left : Position.Right, id: name, isConnectable: false, className: css({
|
|
9
|
+
return (_jsx(Flex, { full: true, direction: "column", align: type === 'input' ? 'start' : 'end', children: handles.map(({ type: handleType, id, blocking, queueSize, name, maxQueueSize, fps }) => (_jsxs(Flex, { position: "relative", align: "end", direction: handleType === 'input' ? 'row' : 'row-reverse', children: [_jsx(Handle, { type: handleType === 'input' ? 'target' : 'source', position: handleType === 'input' ? Position.Left : Position.Right, id: name, isConnectable: false, className: css({
|
|
10
10
|
width: 'custom.handle.dot!',
|
|
11
11
|
height: 'custom.handle.dot!',
|
|
12
12
|
backgroundColor: blocking ? 'dark.warning!' : 'dark.success!',
|
|
13
13
|
border: 'none!',
|
|
14
|
-
}) }), _jsx(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
}) }), _jsx(NodeHandlesSubLabel, { type: type, name: name, queueSize: queueSize, maxQueueSize: maxQueueSize, fps: fps })] }, id))) }));
|
|
15
|
+
};
|
|
16
|
+
const NodeHandlesSubLabel = props => {
|
|
17
|
+
const { type, name, queueSize, maxQueueSize, fps } = props;
|
|
18
|
+
return (_jsx(SubLabel, { className: css({
|
|
19
|
+
...(type === 'input' //
|
|
20
|
+
? { marginLeft: 'xs' }
|
|
21
|
+
: { marginRight: 'xs' }),
|
|
22
|
+
}), text: `[${fps ? `${fps.toFixed(1)} | ` : ''}${maxQueueSize ? `${maxQueueSize}/${queueSize}` : queueSize}] ${name}`, break: "none" }));
|
|
19
23
|
};
|
|
20
24
|
export const PipelineNode = props => {
|
|
21
25
|
const { data: node } = props;
|
|
@@ -38,9 +42,21 @@ export const PipelineNode = props => {
|
|
|
38
42
|
}), children: [_jsx("span", { className: css({
|
|
39
43
|
width: 'icon.sm',
|
|
40
44
|
height: 'icon.sm',
|
|
41
|
-
}) }), _jsx(Label, { text: node.name, color: "unset" }), _jsx(Button, { variant: "ghost", color: "transparent", icon: HelpIcon, onClick: () => window.open(link, '_blank'), className: clsx('node-help-icon', css({
|
|
45
|
+
}) }), _jsx(Label, { text: node.id ? `${node.name} (${node.id})` : node.name, color: "unset" }), _jsx(Button, { variant: "ghost", color: "transparent", icon: HelpIcon, onClick: () => window.open(link, '_blank'), className: clsx('node-help-icon', css({
|
|
42
46
|
width: 'auto',
|
|
43
47
|
height: 'auto',
|
|
44
48
|
right: 'xs',
|
|
45
|
-
})) })] }),
|
|
49
|
+
})) })] }), _jsx(Handle, { type: "target", position: Position.Top, id: "top", isConnectable: false, className: css({
|
|
50
|
+
width: 'custom.handle.dot!',
|
|
51
|
+
height: 'custom.handle.dot!',
|
|
52
|
+
}), style: {
|
|
53
|
+
border: 'none',
|
|
54
|
+
background: 'transparent',
|
|
55
|
+
} }), _jsxs(Flex, { gap: "sm", paddingY: "xs", children: [_jsx(NodeHandles, { type: "input", handles: node.handles.input }), _jsx(NodeHandles, { type: "output", handles: node.handles.output })] }), _jsx(Handle, { type: "source", position: Position.Bottom, id: "bottom", isConnectable: false, className: css({
|
|
56
|
+
width: 'custom.handle.dot!',
|
|
57
|
+
height: 'custom.handle.dot!',
|
|
58
|
+
}), style: {
|
|
59
|
+
border: 'none',
|
|
60
|
+
background: 'transparent',
|
|
61
|
+
} })] }));
|
|
46
62
|
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { FlexProps } from '@luxonis/common-fe-components';
|
|
3
|
-
import type { Pipeline } from '../services/pipeline.js';
|
|
3
|
+
import type { ParsedNode, Pipeline } from '../services/pipeline.js';
|
|
4
|
+
import type { PipelineState } from '../services/pipeline-state.js';
|
|
4
5
|
export type PipelineCanvasProps = FlexProps & {
|
|
5
6
|
pipeline: Pipeline | null;
|
|
7
|
+
pipelineState?: PipelineState[] | null;
|
|
6
8
|
};
|
|
9
|
+
export declare const updateNodesOnPipelineStateChange: (nodes: ParsedNode[], pipelineState: PipelineState[]) => ParsedNode[];
|
|
7
10
|
export declare const PipelineCanvas: React.FC<PipelineCanvasProps>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { ReactFlow, ReactFlowProvider, useEdgesState, useNodesState, useReactFlow, useStore, } from '@xyflow/react';
|
|
3
|
+
import { ReactFlow, ReactFlowProvider, useEdgesState, useNodesInitialized, useNodesState, useReactFlow, useStore, } from '@xyflow/react';
|
|
4
4
|
import { Flex, Header } from '@luxonis/common-fe-components';
|
|
5
5
|
import Dagre from '@dagrejs/dagre';
|
|
6
6
|
import { PipelineNode } from './Node.js';
|
|
@@ -29,13 +29,116 @@ const getLayoutedElements = (nodes, edges) => {
|
|
|
29
29
|
edges,
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
|
-
const
|
|
32
|
+
const adjustNodes = (nodes) => {
|
|
33
|
+
const PADDING = 16;
|
|
34
|
+
const positionedNodes = nodes
|
|
35
|
+
.filter(node => node.type !== 'group')
|
|
36
|
+
.map((node) => {
|
|
37
|
+
const position = node.position;
|
|
38
|
+
const x = position.x - (node.measured?.width ?? 200) / 2;
|
|
39
|
+
const y = position.y - (node.measured?.height ?? 100) / 2;
|
|
40
|
+
return {
|
|
41
|
+
...node,
|
|
42
|
+
position: { x, y },
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
const groupNodes = nodes.filter(node => node.type === 'group');
|
|
46
|
+
const positionedGroups = groupNodes.map(parent => {
|
|
47
|
+
const children = positionedNodes.filter(n => n.parentId === parent.id);
|
|
48
|
+
if (children.length === 0) {
|
|
49
|
+
return { ...parent, position: { x: 0, y: 0 } };
|
|
50
|
+
}
|
|
51
|
+
let minX = 9999;
|
|
52
|
+
let minY = 9999;
|
|
53
|
+
let maxX = -9999;
|
|
54
|
+
let maxY = -9999;
|
|
55
|
+
// eslint-disable-next-line github/array-foreach
|
|
56
|
+
children.forEach(child => {
|
|
57
|
+
const width = child.measured?.width ?? 200;
|
|
58
|
+
const height = child.measured?.height ?? 100;
|
|
59
|
+
minX = Math.min(minX, child.position.x);
|
|
60
|
+
minY = Math.min(minY, child.position.y);
|
|
61
|
+
maxX = Math.max(maxX, child.position.x + width);
|
|
62
|
+
maxY = Math.max(maxY, child.position.y + height);
|
|
63
|
+
});
|
|
64
|
+
const parentX = minX - PADDING;
|
|
65
|
+
const parentY = minY - PADDING;
|
|
66
|
+
// eslint-disable-next-line github/array-foreach
|
|
67
|
+
children.forEach(child => {
|
|
68
|
+
child.position.x -= parentX;
|
|
69
|
+
child.position.y -= parentY;
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
...parent,
|
|
73
|
+
position: { x: parentX, y: parentY },
|
|
74
|
+
measured: {
|
|
75
|
+
width: maxX - minX + PADDING * 2,
|
|
76
|
+
height: maxY - minY + PADDING * 2,
|
|
77
|
+
},
|
|
78
|
+
width: maxX - minX + PADDING * 2,
|
|
79
|
+
height: maxY - minY + PADDING * 2,
|
|
80
|
+
style: {
|
|
81
|
+
...parent.style,
|
|
82
|
+
width: maxX - minX + PADDING * 2,
|
|
83
|
+
height: maxY - minY + PADDING * 2,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
return [...positionedGroups, ...positionedNodes];
|
|
88
|
+
};
|
|
89
|
+
export const updateNodesOnPipelineStateChange = (nodes, pipelineState) => {
|
|
90
|
+
const parsedNodes = [];
|
|
91
|
+
for (const node of nodes) {
|
|
92
|
+
const nodeState = pipelineState.find(state => state.id.toString() === node.id.toString());
|
|
93
|
+
const inputHandles = node.data.handles.input;
|
|
94
|
+
const outputHandles = node.data.handles.output;
|
|
95
|
+
const newInputHandles = [];
|
|
96
|
+
for (const inputHandle of inputHandles) {
|
|
97
|
+
const obj = { ...inputHandle };
|
|
98
|
+
const inputState = nodeState?.inputs[inputHandle.name];
|
|
99
|
+
if (inputState) {
|
|
100
|
+
obj.maxQueueSize = inputState.numQueued;
|
|
101
|
+
obj.fps = inputState.timing.fps;
|
|
102
|
+
}
|
|
103
|
+
newInputHandles.push(obj);
|
|
104
|
+
}
|
|
105
|
+
const newOutputHandles = [];
|
|
106
|
+
for (const outputHandle of outputHandles) {
|
|
107
|
+
const obj = { ...outputHandle };
|
|
108
|
+
const outputState = nodeState?.outputs[outputHandle.name];
|
|
109
|
+
if (outputState) {
|
|
110
|
+
obj.maxQueueSize = outputState.numQueued;
|
|
111
|
+
obj.fps = outputState.timing.fps;
|
|
112
|
+
}
|
|
113
|
+
newOutputHandles.push(obj);
|
|
114
|
+
}
|
|
115
|
+
parsedNodes.push({
|
|
116
|
+
...node,
|
|
117
|
+
data: {
|
|
118
|
+
...node.data,
|
|
119
|
+
handles: {
|
|
120
|
+
input: newInputHandles,
|
|
121
|
+
output: newOutputHandles,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return parsedNodes;
|
|
127
|
+
};
|
|
128
|
+
const PipelineCanvasBody = ({ pipeline,
|
|
129
|
+
// eslint-disable-next-line no-warning-comments
|
|
130
|
+
// TODO: Remove optional after pipelineState is implemented in Viewer and Visualizer
|
|
131
|
+
pipelineState = null, ...flexProps }) => {
|
|
33
132
|
const { fitView, setViewport, getViewport } = useReactFlow();
|
|
34
133
|
const autoArrangeRef = React.useRef(true);
|
|
35
134
|
const widthSelector = (state) => state.width;
|
|
36
135
|
const heightSelector = (state) => state.height;
|
|
37
136
|
const reactFlowWidth = useStore(widthSelector);
|
|
38
137
|
const reactFlowHeight = useStore(heightSelector);
|
|
138
|
+
const nodesInitialized = useNodesInitialized();
|
|
139
|
+
const [isAutoLayoutingFinished, setIsAutoLayoutingFinished] = React.useState(false);
|
|
140
|
+
const [isNodesUpdatedWithState, setIsNodesUpdatedWithState] = React.useState(false);
|
|
141
|
+
const [shouldFitAndResize, setShouldFitAndResize] = React.useState(false);
|
|
39
142
|
React.useEffect(() => {
|
|
40
143
|
void fitView();
|
|
41
144
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -50,6 +153,24 @@ const PipelineCanvasBody = ({ pipeline, ...flexProps }) => {
|
|
|
50
153
|
setNodes([...layouted.nodes]);
|
|
51
154
|
setEdges([...layouted.edges]);
|
|
52
155
|
}, [pipeline?.edges, pipeline?.nodes, setEdges, setNodes]);
|
|
156
|
+
React.useEffect(() => {
|
|
157
|
+
if (nodesInitialized && !isAutoLayoutingFinished) {
|
|
158
|
+
const adjustedNodes = adjustNodes(nodes);
|
|
159
|
+
setNodes([...adjustedNodes]);
|
|
160
|
+
setIsAutoLayoutingFinished(true);
|
|
161
|
+
setShouldFitAndResize(true);
|
|
162
|
+
}
|
|
163
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
164
|
+
}, [nodesInitialized, isAutoLayoutingFinished]);
|
|
165
|
+
React.useEffect(() => {
|
|
166
|
+
if (pipelineState && nodes.length > 0 && !isNodesUpdatedWithState) {
|
|
167
|
+
const updatedNodes = updateNodesOnPipelineStateChange(nodes, pipelineState);
|
|
168
|
+
setNodes([...updatedNodes]);
|
|
169
|
+
setIsNodesUpdatedWithState(true);
|
|
170
|
+
setShouldFitAndResize(true);
|
|
171
|
+
}
|
|
172
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
+
}, [pipelineState, nodes, isNodesUpdatedWithState]);
|
|
53
174
|
const setViewportAndFit = async (x, y, zoom, nds) => {
|
|
54
175
|
await setViewport({ x, y, zoom });
|
|
55
176
|
await fitView({ nodes: nds });
|
|
@@ -64,6 +185,14 @@ const PipelineCanvasBody = ({ pipeline, ...flexProps }) => {
|
|
|
64
185
|
}
|
|
65
186
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
187
|
}, [nodes, edges]);
|
|
188
|
+
React.useEffect(() => {
|
|
189
|
+
if (shouldFitAndResize) {
|
|
190
|
+
const viewport = getViewport();
|
|
191
|
+
void setViewportAndFit(viewport.x, viewport.y, viewport.zoom, nodes);
|
|
192
|
+
setShouldFitAndResize(false);
|
|
193
|
+
}
|
|
194
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
195
|
+
}, [shouldFitAndResize]);
|
|
67
196
|
return (_jsxs(Flex, { align: "center", justify: "center", full: true, height: "container.xs", rounded: "common", border: "base", ...flexProps, children: [!pipeline && _jsx(Header, { text: "Loading pipeline..." }), pipeline && (_jsx(ReactFlow, { nodes: nodes, edges: edges, onNodeDragStart: () => (autoArrangeRef.current = false), onNodesChange: onNodesChange, fitView: true, nodeTypes: { generic: PipelineNode }, minZoom: 0.4 }))] }));
|
|
68
197
|
};
|
|
69
198
|
export const PipelineCanvas = props => (_jsx(ReactFlowProvider, { children: _jsx(PipelineCanvasBody, { ...props }) }));
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { parsePipeline } from './services/pipeline.js';
|
|
2
2
|
export type { Pipeline, RawPipelinePayload } from './services/pipeline.js';
|
|
3
|
+
export { parsePipelineState } from './services/pipeline-state.js';
|
|
4
|
+
export type { PipelineState, RawPipelineStatePayload } from './services/pipeline-state.js';
|
|
3
5
|
export { PipelineCanvas } from './components/PipelineCanvas.js';
|
|
4
6
|
export type { PipelineCanvasProps } from './components/PipelineCanvas.js';
|
package/dist/src/index.js
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type RawPipelineStatePayload = {
|
|
2
|
+
nodeStates: RawPipelineState[];
|
|
3
|
+
};
|
|
4
|
+
export type IOStates = {
|
|
5
|
+
[key: string]: {
|
|
6
|
+
numQueued: number;
|
|
7
|
+
timing: TimingWithFps;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
type Timing = {
|
|
11
|
+
averageMicrosRecent: number;
|
|
12
|
+
maxMicros: number;
|
|
13
|
+
maxMicrosRecent: number;
|
|
14
|
+
medianMicrosRecent: number;
|
|
15
|
+
minMicros: number;
|
|
16
|
+
minMicrosRecent: number;
|
|
17
|
+
stdDevMicrosRecent: number;
|
|
18
|
+
};
|
|
19
|
+
type TimingWithFps = {
|
|
20
|
+
durationStats: Timing;
|
|
21
|
+
fps: number;
|
|
22
|
+
};
|
|
23
|
+
export type RawPipelineState = [
|
|
24
|
+
number,
|
|
25
|
+
{
|
|
26
|
+
events: any[];
|
|
27
|
+
inputStates: IOStates;
|
|
28
|
+
inputsGetTiming: TimingWithFps;
|
|
29
|
+
mainLoopTiming: TimingWithFps;
|
|
30
|
+
otherTimings: object;
|
|
31
|
+
outputStates: IOStates;
|
|
32
|
+
outputsSendTiming: TimingWithFps;
|
|
33
|
+
state: number;
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
export type PipelineState = {
|
|
37
|
+
id: number;
|
|
38
|
+
inputs: IOStates;
|
|
39
|
+
outputs: IOStates;
|
|
40
|
+
};
|
|
41
|
+
export declare function parsePipelineState(rawPayload: RawPipelineStatePayload): PipelineState[];
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function parsePipelineState(rawPayload) {
|
|
2
|
+
const { nodeStates } = rawPayload;
|
|
3
|
+
const parsedNodeStates = [];
|
|
4
|
+
for (const [nodeId, nodeState] of nodeStates) {
|
|
5
|
+
const currentNode = {
|
|
6
|
+
id: nodeId,
|
|
7
|
+
inputs: nodeState.inputStates,
|
|
8
|
+
outputs: nodeState.outputStates,
|
|
9
|
+
};
|
|
10
|
+
parsedNodeStates.push(currentNode);
|
|
11
|
+
}
|
|
12
|
+
return parsedNodeStates;
|
|
13
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Edge, type Node } from '@xyflow/react';
|
|
2
2
|
export type RawPipelineNodeIO = [
|
|
3
3
|
[
|
|
4
4
|
string,
|
|
@@ -16,7 +16,9 @@ export type RawPipelineNode = {
|
|
|
16
16
|
id: number;
|
|
17
17
|
ioInfo: RawPipelineNodeIO[];
|
|
18
18
|
name: string;
|
|
19
|
+
parentId?: number;
|
|
19
20
|
};
|
|
21
|
+
export type RawPipelineBridge = [number, number];
|
|
20
22
|
export type RawPipelineEdge = {
|
|
21
23
|
node1Id: number;
|
|
22
24
|
node1Output: string;
|
|
@@ -29,6 +31,7 @@ export type RawPipelinePayload = {
|
|
|
29
31
|
export type RawPipeline = {
|
|
30
32
|
connections: RawPipelineEdge[];
|
|
31
33
|
nodes: [number, RawPipelineNode][];
|
|
34
|
+
bridges?: [number, number][];
|
|
32
35
|
};
|
|
33
36
|
export type Pipeline = {
|
|
34
37
|
nodes: ParsedNode[];
|
|
@@ -40,8 +43,12 @@ export type ParsedHandle = {
|
|
|
40
43
|
type: 'input' | 'output';
|
|
41
44
|
blocking: boolean;
|
|
42
45
|
queueSize: number;
|
|
46
|
+
maxQueueSize?: number;
|
|
47
|
+
fps?: number;
|
|
43
48
|
};
|
|
44
49
|
export type ParsedNode = Node<{
|
|
50
|
+
id: string;
|
|
51
|
+
parentId?: string;
|
|
45
52
|
name: string;
|
|
46
53
|
handles: {
|
|
47
54
|
input: ParsedHandle[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MarkerType } from '@xyflow/react';
|
|
1
2
|
function parseHandles(handles) {
|
|
2
3
|
const parsedHandles = {
|
|
3
4
|
input: [],
|
|
@@ -24,19 +25,61 @@ export function parsePipeline(rawPayload) {
|
|
|
24
25
|
type: 'generic',
|
|
25
26
|
id: id.toString(),
|
|
26
27
|
position: { x: 0, y: 0 },
|
|
28
|
+
parentId: node.parentId?.toString() === '-1' ? undefined : node.parentId?.toString(),
|
|
29
|
+
extent: node.parentId?.toString() === '-1' ? undefined : 'parent',
|
|
27
30
|
data: {
|
|
31
|
+
id: id.toString(),
|
|
28
32
|
name: node.name,
|
|
29
33
|
handles: parseHandles(node.ioInfo),
|
|
30
34
|
},
|
|
31
35
|
})) ?? [];
|
|
36
|
+
const mappedParentNodes = nodes.map(node => node.parentId).filter(id => id !== undefined);
|
|
37
|
+
const filteredParentNodes = mappedParentNodes.filter(id => id !== '-1');
|
|
38
|
+
const parentNodes = [...new Set(filteredParentNodes)];
|
|
39
|
+
const parentNodesArr = parentNodes
|
|
40
|
+
.map(id => pipeline.nodes.find(([_, node]) => node.id.toString() === id))
|
|
41
|
+
.filter(node => node !== undefined);
|
|
42
|
+
const formattedParentNodes = parentNodesArr.map(([id, node]) => ({
|
|
43
|
+
type: 'group',
|
|
44
|
+
id: id.toString(),
|
|
45
|
+
position: { x: 0, y: 0 },
|
|
46
|
+
parentId: node.parentId?.toString() === '-1' ? undefined : node.parentId?.toString(),
|
|
47
|
+
data: {
|
|
48
|
+
id: id.toString(),
|
|
49
|
+
name: node.name,
|
|
50
|
+
handles: parseHandles(node.ioInfo),
|
|
51
|
+
},
|
|
52
|
+
style: {
|
|
53
|
+
padding: 0,
|
|
54
|
+
borderStyle: 'dashed',
|
|
55
|
+
background: 'rgba(0,0,0,0.125)',
|
|
56
|
+
},
|
|
57
|
+
})) ?? [];
|
|
32
58
|
const edges = pipeline.connections.map(connection => ({
|
|
33
|
-
id: `${connection.node1Id}-${connection.node2Id}`,
|
|
59
|
+
id: `${connection.node1Id}-${connection.node2Id}-${connection.node1Output}-${connection.node2Input}-edge`,
|
|
34
60
|
source: connection.node1Id.toString(),
|
|
35
61
|
target: connection.node2Id.toString(),
|
|
36
62
|
sourceHandle: connection.node1Output,
|
|
37
63
|
targetHandle: connection.node2Input,
|
|
38
64
|
})) ?? [];
|
|
39
|
-
|
|
65
|
+
const bridges = pipeline.bridges?.map(bridge => ({
|
|
66
|
+
id: `${bridge[0]}-${bridge[1]}-bridge`,
|
|
67
|
+
source: bridge[0].toString(),
|
|
68
|
+
target: bridge[1].toString(),
|
|
69
|
+
sourceHandle: 'bottom',
|
|
70
|
+
targetHandle: 'top',
|
|
71
|
+
animated: true,
|
|
72
|
+
markerStart: {
|
|
73
|
+
type: MarkerType.ArrowClosed,
|
|
74
|
+
},
|
|
75
|
+
markerEnd: {
|
|
76
|
+
type: MarkerType.ArrowClosed,
|
|
77
|
+
},
|
|
78
|
+
type: 'step',
|
|
79
|
+
})) ?? [];
|
|
80
|
+
const groupedNodes = [...formattedParentNodes, ...nodes];
|
|
81
|
+
// NOTE: Parent nodes should be rendered before child nodes
|
|
82
|
+
return { nodes: [...groupedNodes], edges: [...edges, ...bridges] };
|
|
40
83
|
}
|
|
41
84
|
export const DOCS_BASE_URL = `https://docs.luxonis.com/software-v3/depthai/depthai-components/nodes`;
|
|
42
85
|
export const NodesWithLinks = {
|
package/package.json
CHANGED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
@layer utilities {
|
|
2
|
-
|
|
3
|
-
.bg_dark\.warning\! {
|
|
4
|
-
background-color: var(--colors-dark-warning) !important
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.bg_dark\.success\! {
|
|
8
|
-
background-color: var(--colors-dark-success) !important
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.w_custom\.handle\.dot\! {
|
|
12
|
-
width: var(--sizes-custom-handle-dot) !important
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.h_custom\.handle\.dot\! {
|
|
16
|
-
height: var(--sizes-custom-handle-dot) !important
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.border_none\! {
|
|
20
|
-
border: var(--borders-none) !important
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.ml_xs {
|
|
24
|
-
margin-left: var(--spacing-xs)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.mr_xs {
|
|
28
|
-
margin-right: var(--spacing-xs)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.min-w_container\.smaller\.xxs {
|
|
32
|
-
min-width: var(--sizes-container-smaller-xxs)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.border_base {
|
|
36
|
-
border: var(--borders-base)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.rounded_common {
|
|
40
|
-
border-radius: var(--radii-common)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.bg_white {
|
|
44
|
-
background-color: var(--colors-white)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.w_full {
|
|
48
|
-
width: var(--sizes-full)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.bg_light\.gray {
|
|
52
|
-
background-color: var(--colors-light-gray)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.rounded-t_common {
|
|
56
|
-
border-top-left-radius: var(--radii-common);
|
|
57
|
-
border-top-right-radius: var(--radii-common)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.w_icon\.sm {
|
|
61
|
-
width: var(--sizes-icon-sm)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.h_icon\.sm {
|
|
65
|
-
height: var(--sizes-icon-sm)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.w_auto {
|
|
69
|
-
width: auto
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.h_auto {
|
|
73
|
-
height: auto
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.right_xs {
|
|
77
|
-
right: var(--spacing-xs)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.text_unset {
|
|
81
|
-
color: unset
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.text_transparent {
|
|
85
|
-
color: var(--colors-transparent)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.items_start {
|
|
89
|
-
align-items: start
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.flex_row {
|
|
93
|
-
flex-direction: row
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.flex_row-reverse {
|
|
97
|
-
flex-direction: row-reverse
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.items_end {
|
|
101
|
-
align-items: end
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.pos_relative {
|
|
105
|
-
position: relative
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.flex_column {
|
|
109
|
-
flex-direction: column
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.items_center {
|
|
113
|
-
align-items: center
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.justify_space-between {
|
|
117
|
-
justify-content: space-between
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.gap_xs {
|
|
121
|
-
gap: var(--spacing-xs)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.d_flex {
|
|
125
|
-
display: flex
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.gap_sm {
|
|
129
|
-
gap: var(--spacing-sm)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.py_xs {
|
|
133
|
-
padding-block: var(--spacing-xs)
|
|
134
|
-
}
|
|
135
|
-
.\[\&\:hover_\.node-help-icon\]\:text_text\.normal:hover .node-help-icon {
|
|
136
|
-
color: var(--colors-text-normal)
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
@layer recipes {
|
|
141
|
-
.button--variant_ghost:is(:hover, [data-hover]) {
|
|
142
|
-
background: var(--colors-accent);
|
|
143
|
-
color: var(--colors-accent-foreground)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.button--size_default {
|
|
147
|
-
height: var(--sizes-10);
|
|
148
|
-
padding-inline: var(--spacing-4);
|
|
149
|
-
padding-block: var(--spacing-2)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@layer _base {
|
|
153
|
-
.label {
|
|
154
|
-
font-size: 0.875rem;
|
|
155
|
-
line-height: var(--line-heights-none);
|
|
156
|
-
font-weight: var(--font-weights-medium);
|
|
157
|
-
}
|
|
158
|
-
.peer:is(:disabled, [disabled], [data-disabled]) ~ .label {
|
|
159
|
-
cursor: not-allowed;
|
|
160
|
-
opacity: 0.7
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
@layer _base {
|
|
165
|
-
.button {
|
|
166
|
-
display: inline-flex;
|
|
167
|
-
align-items: center;
|
|
168
|
-
justify-content: center;
|
|
169
|
-
border-radius: var(--radii-md);
|
|
170
|
-
font-size: 0.875rem;
|
|
171
|
-
line-height: 1.25rem;
|
|
172
|
-
font-weight: var(--font-weights-medium);
|
|
173
|
-
transition-property: var(--transition-prop, color, background-color, border-color, outline-color, text-decoration-color, fill, stroke);
|
|
174
|
-
transition-timing-function: var(--transition-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
175
|
-
transition-duration: var(--transition-duration, 150ms);
|
|
176
|
-
cursor: pointer;
|
|
177
|
-
--shadow-panda-ring-offset-color: var(--colors-background);
|
|
178
|
-
gap: var(--spacing-2);
|
|
179
|
-
}
|
|
180
|
-
.button:is(:disabled, [disabled], [data-disabled]) {
|
|
181
|
-
pointer-events: none;
|
|
182
|
-
opacity: 50%
|
|
183
|
-
}
|
|
184
|
-
.button:is(:focus-visible, [data-focus-visible]) {
|
|
185
|
-
outline: 2px solid transparent;
|
|
186
|
-
outline-offset: 2px;
|
|
187
|
-
--shadow-panda-ring-offset-shadow: var(--shadow-panda-ring-inset,) 0 0 0 var(--shadow-panda-ring-offset-width, 0px) var(--shadow-panda-ring-offset-color);
|
|
188
|
-
--shadow-panda-ring-shadow: var(--shadow-panda-ring-inset,) 0 0 0 calc(2px + var(--shadow-panda-ring-offset-width, 0px)) var(--shadow-panda-ring-color);
|
|
189
|
-
box-shadow: var(--shadow-panda-ring-offset-shadow),var(--shadow-panda-ring-shadow),var(--shadow-panda-base-shadow,0 0 #0000);
|
|
190
|
-
--shadow-panda-ring-color: var(--colors-ring)
|
|
191
|
-
;
|
|
192
|
-
--shadow-panda-ring-offset-width: 2px
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
@layer utilities {
|
|
2
|
-
|
|
3
|
-
.d_flex {
|
|
4
|
-
display: flex
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
.items_center {
|
|
8
|
-
align-items: center
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.justify_center {
|
|
12
|
-
justify-content: center
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.h_container\.xs {
|
|
16
|
-
height: var(--sizes-container-xs)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.rounded_common {
|
|
20
|
-
border-radius: var(--radii-common)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.border_base {
|
|
24
|
-
border: var(--borders-base)
|
|
25
|
-
}
|
|
26
|
-
}
|