mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-07-27 06:58:28 -06:00
Dynamic Node Importing from Folders Implemented
This commit is contained in:
@ -17,7 +17,8 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogContentText,
|
DialogContentText,
|
||||||
DialogActions
|
DialogActions,
|
||||||
|
Divider
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
|
||||||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
||||||
@ -29,59 +30,34 @@ import ReactFlow, {
|
|||||||
applyNodeChanges,
|
applyNodeChanges,
|
||||||
applyEdgeChanges,
|
applyEdgeChanges,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
useReactFlow,
|
useReactFlow
|
||||||
Handle,
|
|
||||||
Position
|
|
||||||
} from "reactflow";
|
} from "reactflow";
|
||||||
import "reactflow/dist/style.css";
|
import "reactflow/dist/style.css";
|
||||||
import "./Borealis.css";
|
import "./Borealis.css";
|
||||||
|
|
||||||
// ✅ Custom styled node with handles
|
const nodeContext = require.context("./nodes", true, /\.jsx$/);
|
||||||
const CustomNode = ({ data }) => {
|
const nodeTypes = {};
|
||||||
return (
|
const categorizedNodes = {};
|
||||||
<div style={{
|
|
||||||
background: "#2c2c2c",
|
|
||||||
border: "1px solid #3a3a3a",
|
|
||||||
borderRadius: "6px",
|
|
||||||
color: "#ccc",
|
|
||||||
fontSize: "12px",
|
|
||||||
minWidth: "160px",
|
|
||||||
maxWidth: "260px",
|
|
||||||
boxShadow: `
|
|
||||||
0 0 5px rgba(88, 166, 255, 0.1),
|
|
||||||
0 0 10px rgba(88, 166, 255, 0.1)
|
|
||||||
`,
|
|
||||||
position: "relative",
|
|
||||||
transition: "box-shadow 0.3s ease-in-out"
|
|
||||||
}}>
|
|
||||||
<Handle
|
|
||||||
type="target"
|
|
||||||
position={Position.Left}
|
|
||||||
style={{ background: "#58a6ff", width: 10, height: 10 }}
|
|
||||||
/>
|
|
||||||
<Handle
|
|
||||||
type="source"
|
|
||||||
position={Position.Right}
|
|
||||||
style={{ background: "#58a6ff", width: 10, height: 10 }}
|
|
||||||
/>
|
|
||||||
<div style={{
|
|
||||||
background: "#232323",
|
|
||||||
padding: "6px 10px",
|
|
||||||
borderTopLeftRadius: "6px",
|
|
||||||
borderTopRightRadius: "6px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
fontSize: "13px"
|
|
||||||
}}>
|
|
||||||
{data.label || "Custom Node"}
|
|
||||||
</div>
|
|
||||||
<div style={{ padding: "10px" }}>
|
|
||||||
{data.content || "Placeholder"}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function FlowEditor({ nodes, edges, setNodes, setEdges }) {
|
nodeContext.keys().forEach((path) => {
|
||||||
|
const mod = nodeContext(path);
|
||||||
|
if (!mod.default) return;
|
||||||
|
const { type, label, component } = mod.default;
|
||||||
|
if (!type || !component) return;
|
||||||
|
|
||||||
|
const pathParts = path.replace("./", "").split("/");
|
||||||
|
if (pathParts.length < 2) return;
|
||||||
|
const category = pathParts[0];
|
||||||
|
|
||||||
|
if (!categorizedNodes[category]) {
|
||||||
|
categorizedNodes[category] = [];
|
||||||
|
}
|
||||||
|
categorizedNodes[category].push({ type, label });
|
||||||
|
|
||||||
|
nodeTypes[type] = component;
|
||||||
|
});
|
||||||
|
|
||||||
|
function FlowEditor({ nodes, edges, setNodes, setEdges, nodeTypes }) {
|
||||||
const reactFlowWrapper = useRef(null);
|
const reactFlowWrapper = useRef(null);
|
||||||
const { project } = useReactFlow();
|
const { project } = useReactFlow();
|
||||||
|
|
||||||
@ -98,13 +74,18 @@ function FlowEditor({ nodes, edges, setNodes, setEdges }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const id = `node-${Date.now()}`;
|
const id = `node-${Date.now()}`;
|
||||||
|
|
||||||
|
const nodeMeta = Object.values(categorizedNodes)
|
||||||
|
.flat()
|
||||||
|
.find((n) => n.type === type);
|
||||||
|
|
||||||
const newNode = {
|
const newNode = {
|
||||||
id,
|
id,
|
||||||
type: "custom",
|
type,
|
||||||
position,
|
position,
|
||||||
data: {
|
data: {
|
||||||
label: "Custom Node",
|
label: nodeMeta?.label || type,
|
||||||
content: "Placeholder"
|
content: nodeMeta?.label || "Node"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -160,7 +141,7 @@ function FlowEditor({ nodes, edges, setNodes, setEdges }) {
|
|||||||
proOptions={{ hideAttribution: true }}
|
proOptions={{ hideAttribution: true }}
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
edges={edges}
|
edges={edges}
|
||||||
nodeTypes={{ custom: CustomNode }}
|
nodeTypes={nodeTypes}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
@ -300,14 +281,7 @@ export default function App() {
|
|||||||
|
|
||||||
<Box display="flex" flexDirection="column" height="calc(100vh - 64px)">
|
<Box display="flex" flexDirection="column" height="calc(100vh - 64px)">
|
||||||
<Box display="flex" flexGrow={1} minHeight={0}>
|
<Box display="flex" flexGrow={1} minHeight={0}>
|
||||||
<Box
|
<Box sx={{ width: 240, bgcolor: "#121212", borderRight: "1px solid #333", overflowY: "auto" }}>
|
||||||
sx={{
|
|
||||||
width: 240,
|
|
||||||
bgcolor: "#121212",
|
|
||||||
borderRight: "1px solid #333",
|
|
||||||
overflowY: "auto"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Accordion defaultExpanded square disableGutters sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}>
|
<Accordion defaultExpanded square disableGutters sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} sx={accordionHeaderStyle}>
|
<AccordionSummary expandIcon={<ExpandMoreIcon />} sx={accordionHeaderStyle}>
|
||||||
<Typography align="left" sx={{ fontSize: "0.9rem", color: "#0475c2" }}><b>Workflows</b></Typography>
|
<Typography align="left" sx={{ fontSize: "0.9rem", color: "#0475c2" }}><b>Workflows</b></Typography>
|
||||||
@ -319,22 +293,49 @@ export default function App() {
|
|||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|
||||||
<Accordion square disableGutters sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}>
|
<Accordion defaultExpanded square disableGutters sx={{ "&:before": { display: "none" }, margin: 0, border: 0 }}>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} sx={accordionHeaderStyle}>
|
<AccordionSummary expandIcon={<ExpandMoreIcon />} sx={accordionHeaderStyle}>
|
||||||
<Typography align="left" sx={{ fontSize: "0.9rem", color: "#0475c2" }}><b>Nodes</b></Typography>
|
<Typography align="left" sx={{ fontSize: "0.9rem", color: "#0475c2" }}><b>Nodes</b></Typography>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{ p: 0 }}>
|
<AccordionDetails sx={{ p: 0 }}>
|
||||||
<Button
|
{Object.entries(categorizedNodes).map(([category, items]) => (
|
||||||
fullWidth
|
<Box key={category} sx={{ mb: 2 }}>
|
||||||
sx={sidebarBtnStyle}
|
<Divider
|
||||||
draggable
|
sx={{
|
||||||
onDragStart={(event) => {
|
bgcolor: "#2c2c2c",
|
||||||
event.dataTransfer.setData("application/reactflow", "testNode");
|
mb: 1,
|
||||||
event.dataTransfer.effectAllowed = "move";
|
px: 1,
|
||||||
}}
|
py: 0.5,
|
||||||
>
|
display: "flex",
|
||||||
TEST NODE
|
justifyContent: "center"
|
||||||
</Button>
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{
|
||||||
|
color: "#888",
|
||||||
|
fontSize: "0.75rem"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{category}
|
||||||
|
</Typography>
|
||||||
|
</Divider>
|
||||||
|
{items.map(({ type, label }) => (
|
||||||
|
<Button
|
||||||
|
key={`${category}-${type}`}
|
||||||
|
fullWidth
|
||||||
|
sx={sidebarBtnStyle}
|
||||||
|
draggable
|
||||||
|
onDragStart={(event) => {
|
||||||
|
event.dataTransfer.setData("application/reactflow", type);
|
||||||
|
event.dataTransfer.effectAllowed = "move";
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Box>
|
</Box>
|
||||||
@ -346,6 +347,7 @@ export default function App() {
|
|||||||
edges={edges}
|
edges={edges}
|
||||||
setNodes={setNodes}
|
setNodes={setNodes}
|
||||||
setEdges={setEdges}
|
setEdges={setEdges}
|
||||||
|
nodeTypes={nodeTypes}
|
||||||
/>
|
/>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
</Box>
|
</Box>
|
||||||
|
65
Data/WebUI/src/nodes/Experimental/Experimental_Node.jsx
Normal file
65
Data/WebUI/src/nodes/Experimental/Experimental_Node.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// src/nodes/General Purpose/CustomNode.jsx
|
||||||
|
import React from "react";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
const experimentalNode = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#2c2c2c",
|
||||||
|
border: "1px solid #3a3a3a",
|
||||||
|
borderRadius: "6px",
|
||||||
|
color: "#ccc",
|
||||||
|
fontSize: "12px",
|
||||||
|
minWidth: "160px",
|
||||||
|
maxWidth: "260px",
|
||||||
|
boxShadow: `
|
||||||
|
0 0 5px rgba(88, 166, 255, 0.1),
|
||||||
|
0 0 10px rgba(88, 166, 255, 0.1)
|
||||||
|
`,
|
||||||
|
position: "relative",
|
||||||
|
transition: "box-shadow 0.3s ease-in-out"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Left}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type="source"
|
||||||
|
position={Position.Right}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#232323",
|
||||||
|
padding: "6px 10px",
|
||||||
|
borderTopLeftRadius: "6px",
|
||||||
|
borderTopRightRadius: "6px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.label || "Experimental Node"}
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "10px" }}>
|
||||||
|
{data.content || "Experimental Node"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
type: "experimentalNode", // Must match the type used in nodeTypes
|
||||||
|
label: "Experimental Node",
|
||||||
|
component: experimentalNode
|
||||||
|
};
|
65
Data/WebUI/src/nodes/Flyff Universe/Flyff_Node.jsx
Normal file
65
Data/WebUI/src/nodes/Flyff Universe/Flyff_Node.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// src/nodes/General Purpose/CustomNode.jsx
|
||||||
|
import React from "react";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
const flyffNode = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#2c2c2c",
|
||||||
|
border: "1px solid #3a3a3a",
|
||||||
|
borderRadius: "6px",
|
||||||
|
color: "#ccc",
|
||||||
|
fontSize: "12px",
|
||||||
|
minWidth: "160px",
|
||||||
|
maxWidth: "260px",
|
||||||
|
boxShadow: `
|
||||||
|
0 0 5px rgba(88, 166, 255, 0.1),
|
||||||
|
0 0 10px rgba(88, 166, 255, 0.1)
|
||||||
|
`,
|
||||||
|
position: "relative",
|
||||||
|
transition: "box-shadow 0.3s ease-in-out"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Left}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type="source"
|
||||||
|
position={Position.Right}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#232323",
|
||||||
|
padding: "6px 10px",
|
||||||
|
borderTopLeftRadius: "6px",
|
||||||
|
borderTopRightRadius: "6px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.label || "Flyff Node"}
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "10px" }}>
|
||||||
|
{data.content || "Flyff Node"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
type: "flyffNode", // Must match the type used in nodeTypes
|
||||||
|
label: "Flyff Node",
|
||||||
|
component: flyffNode
|
||||||
|
};
|
65
Data/WebUI/src/nodes/General Purpose/Data_Node.jsx
Normal file
65
Data/WebUI/src/nodes/General Purpose/Data_Node.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// src/nodes/General Purpose/CustomNode.jsx
|
||||||
|
import React from "react";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
const dataNode = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#2c2c2c",
|
||||||
|
border: "1px solid #3a3a3a",
|
||||||
|
borderRadius: "6px",
|
||||||
|
color: "#ccc",
|
||||||
|
fontSize: "12px",
|
||||||
|
minWidth: "160px",
|
||||||
|
maxWidth: "260px",
|
||||||
|
boxShadow: `
|
||||||
|
0 0 5px rgba(88, 166, 255, 0.1),
|
||||||
|
0 0 10px rgba(88, 166, 255, 0.1)
|
||||||
|
`,
|
||||||
|
position: "relative",
|
||||||
|
transition: "box-shadow 0.3s ease-in-out"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Left}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type="source"
|
||||||
|
position={Position.Right}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#232323",
|
||||||
|
padding: "6px 10px",
|
||||||
|
borderTopLeftRadius: "6px",
|
||||||
|
borderTopRightRadius: "6px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.label || "Data Node"}
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "10px" }}>
|
||||||
|
{data.content || "Data Node"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
type: "dataNode", // Must match the type used in nodeTypes
|
||||||
|
label: "Data Node",
|
||||||
|
component: dataNode
|
||||||
|
};
|
65
Data/WebUI/src/nodes/Organization/Node_Group_Box.jsx
Normal file
65
Data/WebUI/src/nodes/Organization/Node_Group_Box.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// src/nodes/General Purpose/CustomNode.jsx
|
||||||
|
import React from "react";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
const nodeGroupBox = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#2c2c2c",
|
||||||
|
border: "1px solid #3a3a3a",
|
||||||
|
borderRadius: "6px",
|
||||||
|
color: "#ccc",
|
||||||
|
fontSize: "12px",
|
||||||
|
minWidth: "160px",
|
||||||
|
maxWidth: "260px",
|
||||||
|
boxShadow: `
|
||||||
|
0 0 5px rgba(88, 166, 255, 0.1),
|
||||||
|
0 0 10px rgba(88, 166, 255, 0.1)
|
||||||
|
`,
|
||||||
|
position: "relative",
|
||||||
|
transition: "box-shadow 0.3s ease-in-out"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Left}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type="source"
|
||||||
|
position={Position.Right}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#232323",
|
||||||
|
padding: "6px 10px",
|
||||||
|
borderTopLeftRadius: "6px",
|
||||||
|
borderTopRightRadius: "6px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.label || "Node Group Box"}
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "10px" }}>
|
||||||
|
{data.content || "Node Group Box"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
type: "nodeGroupBox", // Must match the type used in nodeTypes
|
||||||
|
label: "Node Group Box",
|
||||||
|
component: nodeGroupBox
|
||||||
|
};
|
65
Data/WebUI/src/nodes/Reporting/Export_to_CSV.jsx
Normal file
65
Data/WebUI/src/nodes/Reporting/Export_to_CSV.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// src/nodes/General Purpose/CustomNode.jsx
|
||||||
|
import React from "react";
|
||||||
|
import { Handle, Position } from "reactflow";
|
||||||
|
|
||||||
|
const ExportToCSVNode = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#2c2c2c",
|
||||||
|
border: "1px solid #3a3a3a",
|
||||||
|
borderRadius: "6px",
|
||||||
|
color: "#ccc",
|
||||||
|
fontSize: "12px",
|
||||||
|
minWidth: "160px",
|
||||||
|
maxWidth: "260px",
|
||||||
|
boxShadow: `
|
||||||
|
0 0 5px rgba(88, 166, 255, 0.1),
|
||||||
|
0 0 10px rgba(88, 166, 255, 0.1)
|
||||||
|
`,
|
||||||
|
position: "relative",
|
||||||
|
transition: "box-shadow 0.3s ease-in-out"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Handle
|
||||||
|
type="target"
|
||||||
|
position={Position.Left}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
type="source"
|
||||||
|
position={Position.Right}
|
||||||
|
style={{
|
||||||
|
background: "#58a6ff",
|
||||||
|
width: 10,
|
||||||
|
height: 10
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#232323",
|
||||||
|
padding: "6px 10px",
|
||||||
|
borderTopLeftRadius: "6px",
|
||||||
|
borderTopRightRadius: "6px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data.label || "Export to CSV"}
|
||||||
|
</div>
|
||||||
|
<div style={{ padding: "10px" }}>
|
||||||
|
{data.content || "Export to CSV"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
type: "ExportToCSVNode", // Must match the type used in nodeTypes
|
||||||
|
label: "Export to CSV",
|
||||||
|
component: ExportToCSVNode
|
||||||
|
};
|
@ -1,14 +0,0 @@
|
|||||||
// Data/WebUI/src/nodes/TestNode.jsx
|
|
||||||
import React from 'react';
|
|
||||||
import { Handle, Position } from 'reactflow';
|
|
||||||
|
|
||||||
export default function TestNode({ data }) {
|
|
||||||
return (
|
|
||||||
<div style={{ background: '#fff', padding: '8px', border: '1px solid #999' }}>
|
|
||||||
<b>Test Node</b>
|
|
||||||
<div>{data.label}</div>
|
|
||||||
<Handle type="target" position={Position.Top} />
|
|
||||||
<Handle type="source" position={Position.Bottom} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
Reference in New Issue
Block a user