Node Configuration Sidebar Milestone 3
This commit is contained in:
parent
6f6fc96d17
commit
cb2a974520
@ -352,23 +352,31 @@ export default function FlowEditor({
|
|||||||
if (nodeCountEl) nodeCountEl.innerText = nodes.length;
|
if (nodeCountEl) nodeCountEl.innerText = nodes.length;
|
||||||
}, [nodes]);
|
}, [nodes]);
|
||||||
|
|
||||||
const selectedNode = nodes.find((n) => n.data?.label === selectedNodeLabel);
|
const selectedNode = nodes.find((n) => n.data?.label === selectedNodeLabel);
|
||||||
const nodeTypeMeta = selectedNode
|
const nodeDef = selectedNode
|
||||||
? Object.values(categorizedNodes).flat().find((def) => def.type === selectedNode.type)
|
? Object.values(categorizedNodes).flat().find((def) => def.type === selectedNode.type)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flow-editor-container"
|
className="flow-editor-container"
|
||||||
ref={wrapperRef}
|
ref={wrapperRef}
|
||||||
style={{ position: "relative" }}
|
style={{ position: "relative" }}
|
||||||
>
|
>
|
||||||
|
|
||||||
<NodeConfigurationSidebar
|
<NodeConfigurationSidebar
|
||||||
drawerOpen={drawerOpen}
|
drawerOpen={drawerOpen}
|
||||||
setDrawerOpen={setDrawerOpen}
|
setDrawerOpen={setDrawerOpen}
|
||||||
title={selectedNodeLabel}
|
title={selectedNode?.data?.label || ""}
|
||||||
nodeData={nodeTypeMeta}
|
nodeData={
|
||||||
|
selectedNode && nodeDef
|
||||||
|
? {
|
||||||
|
...nodeDef,
|
||||||
|
...selectedNode.data,
|
||||||
|
nodeId: selectedNode.id
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/Node_Configuration_Sidebar.jsx
|
////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/Node_Configuration_Sidebar.jsx
|
||||||
import { Box, Typography, Tabs, Tab, TextField } from "@mui/material";
|
import { Box, Typography, Tabs, Tab, TextField } from "@mui/material";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { useReactFlow } from "reactflow";
|
||||||
|
|
||||||
export default function NodeConfigurationSidebar({ drawerOpen, setDrawerOpen, title, nodeData }) {
|
export default function NodeConfigurationSidebar({ drawerOpen, setDrawerOpen, title, nodeData }) {
|
||||||
const [activeTab, setActiveTab] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
|
const { setNodes } = useReactFlow();
|
||||||
const handleTabChange = (_, newValue) => setActiveTab(newValue);
|
const handleTabChange = (_, newValue) => setActiveTab(newValue);
|
||||||
|
|
||||||
const renderConfigFields = () => {
|
const renderConfigFields = () => {
|
||||||
const config = nodeData?.config || [];
|
const config = nodeData?.config || [];
|
||||||
|
const nodeId = nodeData?.nodeId;
|
||||||
|
|
||||||
return config.map((field, index) => (
|
return config.map((field, index) => (
|
||||||
<Box key={index} sx={{ mb: 2 }}>
|
<Box key={index} sx={{ mb: 2 }}>
|
||||||
<Typography variant="body2" sx={{ color: "#ccc", mb: 0.5 }}>
|
<Typography variant="body2" sx={{ color: "#ccc", mb: 0.5 }}>
|
||||||
@ -18,6 +22,18 @@ export default function NodeConfigurationSidebar({ drawerOpen, setDrawerOpen, ti
|
|||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
value={nodeData?.[field.key] || ""}
|
value={nodeData?.[field.key] || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newValue = e.target.value;
|
||||||
|
if (!nodeId) return;
|
||||||
|
setNodes((nds) =>
|
||||||
|
nds.map((n) =>
|
||||||
|
n.id === nodeId
|
||||||
|
? { ...n, data: { ...n.data, [field.key]: newValue } }
|
||||||
|
: n
|
||||||
|
)
|
||||||
|
);
|
||||||
|
window.BorealisValueBus[nodeId] = newValue;
|
||||||
|
}}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
sx: {
|
sx: {
|
||||||
backgroundColor: "#1e1e1e",
|
backgroundColor: "#1e1e1e",
|
||||||
@ -90,7 +106,7 @@ export default function NodeConfigurationSidebar({ drawerOpen, setDrawerOpen, ti
|
|||||||
{activeTab === 0 && renderConfigFields()}
|
{activeTab === 0 && renderConfigFields()}
|
||||||
{activeTab === 1 && (
|
{activeTab === 1 && (
|
||||||
<Typography sx={{ whiteSpace: "pre-wrap", fontSize: "0.85rem", color: "#aaa" }}>
|
<Typography sx={{ whiteSpace: "pre-wrap", fontSize: "0.85rem", color: "#aaa" }}>
|
||||||
{nodeData?.usage_documentation || "No documentation provided for this node."}
|
{nodeData?.usage_documentation || "No usage documentation provided for this node."}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/nodes/General Purpose/Node_Data.jsx
|
////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/nodes/General Purpose/Node_Data.jsx
|
||||||
|
import React, { useEffect, useRef } from "react";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import { Handle, Position, useReactFlow, useStore } from "reactflow";
|
import { Handle, Position, useReactFlow, useStore } from "reactflow";
|
||||||
import { IconButton } from "@mui/material";
|
import { IconButton } from "@mui/material";
|
||||||
import { Settings as SettingsIcon } from "@mui/icons-material";
|
import { Settings as SettingsIcon } from "@mui/icons-material";
|
||||||
@ -11,20 +10,12 @@ if (!window.BorealisUpdateRate) window.BorealisUpdateRate = 100;
|
|||||||
const DataNode = ({ id, data }) => {
|
const DataNode = ({ id, data }) => {
|
||||||
const { setNodes } = useReactFlow();
|
const { setNodes } = useReactFlow();
|
||||||
const edges = useStore((state) => state.edges);
|
const edges = useStore((state) => state.edges);
|
||||||
const [renderValue, setRenderValue] = useState(data?.value || "");
|
const valueRef = useRef(data?.value || "");
|
||||||
const valueRef = useRef(renderValue);
|
|
||||||
|
|
||||||
const handleManualInput = (e) => {
|
useEffect(() => {
|
||||||
const newValue = e.target.value;
|
valueRef.current = data?.value || "";
|
||||||
valueRef.current = newValue;
|
window.BorealisValueBus[id] = valueRef.current;
|
||||||
setRenderValue(newValue);
|
}, [data?.value, id]);
|
||||||
window.BorealisValueBus[id] = newValue;
|
|
||||||
setNodes((nds) =>
|
|
||||||
nds.map((n) =>
|
|
||||||
n.id === id ? { ...n, data: { ...n.data, value: newValue } } : n
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let currentRate = window.BorealisUpdateRate || 100;
|
let currentRate = window.BorealisUpdateRate || 100;
|
||||||
@ -38,7 +29,6 @@ const DataNode = ({ id, data }) => {
|
|||||||
const upstreamValue = window.BorealisValueBus[inputEdge.source] ?? "";
|
const upstreamValue = window.BorealisValueBus[inputEdge.source] ?? "";
|
||||||
if (upstreamValue !== valueRef.current) {
|
if (upstreamValue !== valueRef.current) {
|
||||||
valueRef.current = upstreamValue;
|
valueRef.current = upstreamValue;
|
||||||
setRenderValue(upstreamValue);
|
|
||||||
window.BorealisValueBus[id] = upstreamValue;
|
window.BorealisValueBus[id] = upstreamValue;
|
||||||
setNodes((nds) =>
|
setNodes((nds) =>
|
||||||
nds.map((n) =>
|
nds.map((n) =>
|
||||||
@ -67,9 +57,6 @@ const DataNode = ({ id, data }) => {
|
|||||||
};
|
};
|
||||||
}, [id, setNodes, edges]);
|
}, [id, setNodes, edges]);
|
||||||
|
|
||||||
const inputEdge = edges.find((e) => e?.target === id);
|
|
||||||
const hasInput = Boolean(inputEdge);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="borealis-node">
|
<div className="borealis-node">
|
||||||
<Handle type="target" position={Position.Left} className="borealis-handle" />
|
<Handle type="target" position={Position.Left} className="borealis-handle" />
|
||||||
@ -79,32 +66,13 @@ const DataNode = ({ id, data }) => {
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
window.BorealisOpenDrawer &&
|
window.BorealisOpenDrawer &&
|
||||||
window.BorealisOpenDrawer(data?.label || "Unknown Node", data)
|
window.BorealisOpenDrawer(data?.label || "Unknown Node", { ...data, nodeId: id })
|
||||||
}
|
}
|
||||||
sx={{ padding: 0, marginRight: "-3px", color: "#58a6ff", width: "20px", height: "20px" }}
|
sx={{ padding: 0, marginRight: "-3px", color: "#58a6ff", width: "20px", height: "20px" }}
|
||||||
>
|
>
|
||||||
<SettingsIcon sx={{ fontSize: "16px" }} />
|
<SettingsIcon sx={{ fontSize: "16px" }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
<div className="borealis-node-content">
|
|
||||||
<div style={{ marginBottom: "8px", fontSize: "9px", color: "#ccc" }}>{data?.content}</div>
|
|
||||||
<label style={{ fontSize: "9px", display: "block", marginBottom: "4px" }}>Value:</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={renderValue}
|
|
||||||
onChange={handleManualInput}
|
|
||||||
disabled={hasInput}
|
|
||||||
style={{
|
|
||||||
fontSize: "9px",
|
|
||||||
padding: "4px",
|
|
||||||
background: hasInput ? "#2a2a2a" : "#1e1e1e",
|
|
||||||
color: "#ccc",
|
|
||||||
border: "1px solid #444",
|
|
||||||
borderRadius: "2px",
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Handle type="source" position={Position.Right} className="borealis-handle" />
|
<Handle type="source" position={Position.Right} className="borealis-handle" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -117,7 +85,7 @@ export default {
|
|||||||
content: "Store a String or Number",
|
content: "Store a String or Number",
|
||||||
component: DataNode,
|
component: DataNode,
|
||||||
config: [
|
config: [
|
||||||
{ key: "value", label: "Initial Value", type: "text" }
|
{ key: "value", label: "Value", type: "text" }
|
||||||
],
|
],
|
||||||
usage_documentation: `
|
usage_documentation: `
|
||||||
### DataNode Usage
|
### DataNode Usage
|
||||||
|
Loading…
x
Reference in New Issue
Block a user