- Added Logic Comparison Node
- Added Math Operation Node - Added Data Node - Added (Scaffold) of Backdrop Node - Added Internal Timer Logic for Node Updates - Added Borealis Value Bus to Transmit Data Between Nodes - Updated Powershell Deployment Script - Misc Fixes / Adjustments
This commit is contained in:
parent
d46c6ecc3c
commit
dca79b8556
@ -1,4 +1,7 @@
|
||||
// Core React Imports
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
|
||||
// Material UI - Components
|
||||
import {
|
||||
AppBar,
|
||||
Toolbar,
|
||||
@ -18,31 +21,25 @@ import {
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
Divider
|
||||
Divider,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
|
||||
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
|
||||
// Icons for Sidebar Workflow Buttons
|
||||
import SaveIcon from "@mui/icons-material/Save";
|
||||
import FileOpenIcon from "@mui/icons-material/FileOpen";
|
||||
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
|
||||
|
||||
// Info Icon for About Menu
|
||||
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
||||
|
||||
// Node Icon (Left-Side of Each Node in Sidebar Menu)
|
||||
import PolylineIcon from "@mui/icons-material/Polyline";
|
||||
|
||||
// Gitea Project Icon
|
||||
import MergeTypeIcon from "@mui/icons-material/MergeType";
|
||||
|
||||
// Credits Icon
|
||||
import PeopleIcon from "@mui/icons-material/People";
|
||||
// Material UI - Icons
|
||||
import {
|
||||
DragIndicator as DragIndicatorIcon,
|
||||
KeyboardArrowDown as KeyboardArrowDownIcon,
|
||||
ExpandMore as ExpandMoreIcon,
|
||||
Save as SaveIcon,
|
||||
FileOpen as FileOpenIcon,
|
||||
DeleteForever as DeleteForeverIcon,
|
||||
InfoOutlined as InfoOutlinedIcon,
|
||||
Polyline as PolylineIcon,
|
||||
MergeType as MergeTypeIcon,
|
||||
People as PeopleIcon
|
||||
} from "@mui/icons-material";
|
||||
|
||||
// React Flow
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
addEdge,
|
||||
@ -51,12 +48,14 @@ import ReactFlow, {
|
||||
ReactFlowProvider,
|
||||
useReactFlow
|
||||
} from "reactflow";
|
||||
|
||||
// Styles
|
||||
import "reactflow/dist/style.css";
|
||||
import "./Borealis.css";
|
||||
|
||||
// Global Node Update Timer Variable
|
||||
if (!window.BorealisUpdateRate) {
|
||||
window.BorealisUpdateRate = 100; // Default Update Rate: 100ms
|
||||
window.BorealisUpdateRate = 200; // Default Update Rate: 100ms
|
||||
}
|
||||
|
||||
const nodeContext = require.context("./nodes", true, /\.jsx$/);
|
||||
|
@ -1,20 +0,0 @@
|
||||
import React from "react";
|
||||
import { Handle, Position } from "reactflow";
|
||||
|
||||
const experimentalNode = ({ data }) => {
|
||||
return (
|
||||
<div className="borealis-node">
|
||||
<Handle type="target" position={Position.Left} className="borealis-handle" />
|
||||
<Handle type="source" position={Position.Right} className="borealis-handle" />
|
||||
<div className="borealis-node-header">{data.label || "Experimental Node"}</div>
|
||||
<div className="borealis-node-content">{data.content || "Placeholder Experimental Content"}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
type: "experimentalNode",
|
||||
label: "Experimental Node",
|
||||
defaultContent: "Placeholder Node",
|
||||
component: experimentalNode
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
import React from "react";
|
||||
import { Handle, Position } from "reactflow";
|
||||
|
||||
const flyffNode = ({ data }) => {
|
||||
return (
|
||||
<div className="borealis-node">
|
||||
<Handle type="target" position={Position.Left} className="borealis-handle" />
|
||||
<Handle type="source" position={Position.Right} className="borealis-handle" />
|
||||
<div className="borealis-node-header">{data.label || "Flyff Node"}</div>
|
||||
<div className="borealis-node-content">{data.content || "Placeholder Flyff Content"}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
type: "flyffNode",
|
||||
label: "Flyff Node",
|
||||
defaultContent: "Placeholder Node",
|
||||
component: flyffNode
|
||||
};
|
@ -176,7 +176,7 @@ const DataNode = ({ id, data }) => {
|
||||
|
||||
export default {
|
||||
type: "DataNode", // REQUIRED: unique identifier for the node type
|
||||
label: "Data Node",
|
||||
label: "String / Number Data",
|
||||
description: `
|
||||
Foundational Data Node
|
||||
|
||||
@ -185,6 +185,6 @@ Foundational Data Node
|
||||
- Pushes value to downstream nodes every X ms
|
||||
- Uses BorealisValueBus to communicate with other nodes
|
||||
`.trim(),
|
||||
content: "Store Strings, Ints, and Floats",
|
||||
content: "Store a String or Number",
|
||||
component: DataNode
|
||||
};
|
||||
|
173
Data/WebUI/src/nodes/General Purpose/Logical_Operators.jsx
Normal file
173
Data/WebUI/src/nodes/General Purpose/Logical_Operators.jsx
Normal file
@ -0,0 +1,173 @@
|
||||
/**
|
||||
* ==============================================
|
||||
* Borealis - Comparison Node (Logic Evaluation)
|
||||
* ==============================================
|
||||
*
|
||||
* COMPONENT ROLE:
|
||||
* This node takes two input values and evaluates them using a selected comparison operator.
|
||||
* It returns 1 (true) or 0 (false) depending on the result of the comparison.
|
||||
*
|
||||
* FEATURES:
|
||||
* - Dropdown to select input type: "Number" or "String"
|
||||
* - Dropdown to select comparison operator: ==, !=, >, <, >=, <=
|
||||
* - Dynamically disables numeric-only operators for string inputs
|
||||
* - Automatically resets operator to == when switching to String
|
||||
* - Supports summing multiple inputs per side (A, B)
|
||||
* - For "String" mode: concatenates inputs in connection order
|
||||
* - Uses BorealisValueBus for input/output
|
||||
* - Controlled by global update timer
|
||||
*
|
||||
* STRUCTURE:
|
||||
* - Label and Description
|
||||
* - Input A (top-left) and Input B (middle-left)
|
||||
* - Output (right edge) result: 1 (true) or 0 (false)
|
||||
* - Operator dropdown and Input Type dropdown
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Handle, Position, useReactFlow, useStore } from "reactflow";
|
||||
|
||||
if (!window.BorealisValueBus) window.BorealisValueBus = {};
|
||||
if (!window.BorealisUpdateRate) window.BorealisUpdateRate = 100;
|
||||
|
||||
const ComparisonNode = ({ id, data }) => {
|
||||
const { setNodes } = useReactFlow();
|
||||
const edges = useStore(state => state.edges);
|
||||
|
||||
const [inputType, setInputType] = useState(data?.inputType || "Number");
|
||||
const [operator, setOperator] = useState(data?.operator || "Equal (==)");
|
||||
const [renderValue, setRenderValue] = useState("0");
|
||||
const valueRef = useRef("0");
|
||||
|
||||
useEffect(() => {
|
||||
if (inputType === "String" && !["Equal (==)", "Not Equal (!=)"].includes(operator)) {
|
||||
setOperator("Equal (==)");
|
||||
}
|
||||
}, [inputType]);
|
||||
|
||||
useEffect(() => {
|
||||
let currentRate = window.BorealisUpdateRate;
|
||||
let intervalId = null;
|
||||
|
||||
const runNodeLogic = () => {
|
||||
const edgeInputsA = edges.filter(e => e?.target === id && e.targetHandle === "a");
|
||||
const edgeInputsB = edges.filter(e => e?.target === id && e.targetHandle === "b");
|
||||
|
||||
const extractValues = (edgeList) => {
|
||||
const values = edgeList.map(e => window.BorealisValueBus[e.source]).filter(v => v !== undefined);
|
||||
if (inputType === "Number") {
|
||||
return values.reduce((sum, v) => sum + (parseFloat(v) || 0), 0);
|
||||
}
|
||||
return values.join("");
|
||||
};
|
||||
|
||||
const a = extractValues(edgeInputsA);
|
||||
const b = extractValues(edgeInputsB);
|
||||
|
||||
const resultMap = {
|
||||
"Equal (==)": a === b,
|
||||
"Not Equal (!=)": a !== b,
|
||||
"Greater Than (>)": a > b,
|
||||
"Less Than (<)": a < b,
|
||||
"Greater Than or Equal (>=)": a >= b,
|
||||
"Less Than or Equal (<=)": a <= b
|
||||
};
|
||||
|
||||
const result = resultMap[operator] ? 1 : 0;
|
||||
|
||||
valueRef.current = result;
|
||||
setRenderValue(result);
|
||||
window.BorealisValueBus[id] = result;
|
||||
|
||||
setNodes(nds =>
|
||||
nds.map(n =>
|
||||
n.id === id ? { ...n, data: { ...n.data, value: result, inputType, operator } } : n
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
intervalId = setInterval(runNodeLogic, currentRate);
|
||||
|
||||
const monitor = setInterval(() => {
|
||||
const newRate = window.BorealisUpdateRate;
|
||||
if (newRate !== currentRate) {
|
||||
clearInterval(intervalId);
|
||||
currentRate = newRate;
|
||||
intervalId = setInterval(runNodeLogic, currentRate);
|
||||
}
|
||||
}, 250);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
clearInterval(monitor);
|
||||
};
|
||||
}, [id, edges, inputType, operator, setNodes]);
|
||||
|
||||
return (
|
||||
<div className="borealis-node">
|
||||
<div style={{ position: "absolute", left: -16, top: 12, fontSize: "8px", color: "#ccc" }}>A</div>
|
||||
<div style={{ position: "absolute", left: -16, top: 50, fontSize: "8px", color: "#ccc" }}>B</div>
|
||||
<Handle type="target" position={Position.Left} id="a" style={{ top: 12 }} className="borealis-handle" />
|
||||
<Handle type="target" position={Position.Left} id="b" style={{ top: 50 }} className="borealis-handle" />
|
||||
|
||||
<div className="borealis-node-header">
|
||||
{data?.label || "Comparison Node"}
|
||||
</div>
|
||||
|
||||
<div className="borealis-node-content">
|
||||
<div style={{ marginBottom: "6px", fontSize: "9px", color: "#ccc" }}>
|
||||
{data?.content || "Evaluates A vs B and outputs 1 (true) or 0 (false)."}
|
||||
</div>
|
||||
|
||||
<label style={{ fontSize: "9px" }}>Input Type:</label>
|
||||
<select value={inputType} onChange={(e) => setInputType(e.target.value)} style={dropdownStyle}>
|
||||
<option value="Number">Number</option>
|
||||
<option value="String">String</option>
|
||||
</select>
|
||||
|
||||
<label style={{ fontSize: "9px", marginTop: "6px" }}>Operator:</label>
|
||||
<select value={operator} onChange={(e) => setOperator(e.target.value)} style={dropdownStyle}>
|
||||
<option>Equal (==)</option>
|
||||
<option>Not Equal (!=)</option>
|
||||
<option disabled={inputType === "String"}>Greater Than (>)</option>
|
||||
<option disabled={inputType === "String"}>Less Than (<)</option>
|
||||
<option disabled={inputType === "String"}>Greater Than or Equal (>=)</option>
|
||||
<option disabled={inputType === "String"}>Less Than or Equal (<=)</option>
|
||||
</select>
|
||||
|
||||
<div style={{ marginTop: "8px", fontSize: "9px" }}>Result: {renderValue}</div>
|
||||
</div>
|
||||
|
||||
<Handle type="source" position={Position.Right} className="borealis-handle" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const dropdownStyle = {
|
||||
width: "100%",
|
||||
fontSize: "9px",
|
||||
padding: "4px",
|
||||
background: "#1e1e1e",
|
||||
color: "#ccc",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "2px",
|
||||
marginBottom: "4px"
|
||||
};
|
||||
|
||||
export default {
|
||||
type: "ComparisonNode",
|
||||
label: "Logic Comparison",
|
||||
description: `
|
||||
Compare Two Inputs (A vs B)
|
||||
|
||||
- Uses configurable operator
|
||||
- Supports numeric and string comparison
|
||||
- Aggregates multiple inputs by summing (Number) or joining (String in connection order)
|
||||
- Only == and != are valid for String mode
|
||||
- Automatically resets operator when switching to String mode
|
||||
- Outputs 1 (true) or 0 (false) into BorealisValueBus
|
||||
- Live-updates based on global timer
|
||||
`.trim(),
|
||||
content: "Compare A and B using Logic",
|
||||
component: ComparisonNode
|
||||
};
|
177
Data/WebUI/src/nodes/General Purpose/Math_Operation.jsx
Normal file
177
Data/WebUI/src/nodes/General Purpose/Math_Operation.jsx
Normal file
@ -0,0 +1,177 @@
|
||||
/**
|
||||
* ============================================
|
||||
* Borealis - Math Operation Node (Multi-Input A/B)
|
||||
* ============================================
|
||||
*
|
||||
* COMPONENT ROLE:
|
||||
* Performs live math operations on *two grouped input sets* (A and B).
|
||||
*
|
||||
* FUNCTIONALITY:
|
||||
* - Inputs connected to Handle A are summed
|
||||
* - Inputs connected to Handle B are summed
|
||||
* - Math operation is applied as: A <operator> B
|
||||
* - Result pushed via BorealisValueBus[id]
|
||||
*
|
||||
* SUPPORTED OPERATORS:
|
||||
* - Add, Subtract, Multiply, Divide, Average
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Handle, Position, useReactFlow, useStore } from "reactflow";
|
||||
|
||||
if (!window.BorealisValueBus) window.BorealisValueBus = {};
|
||||
if (!window.BorealisUpdateRate) window.BorealisUpdateRate = 100;
|
||||
|
||||
const MathNode = ({ id, data }) => {
|
||||
const { setNodes } = useReactFlow();
|
||||
const edges = useStore(state => state.edges);
|
||||
|
||||
const [operator, setOperator] = useState(data?.operator || "Add");
|
||||
const [result, setResult] = useState("0");
|
||||
const resultRef = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
let intervalId = null;
|
||||
let currentRate = window.BorealisUpdateRate;
|
||||
|
||||
const runLogic = () => {
|
||||
const inputsA = edges.filter(e => e.target === id && e.targetHandle === "a");
|
||||
const inputsB = edges.filter(e => e.target === id && e.targetHandle === "b");
|
||||
|
||||
const sum = (list) =>
|
||||
list.map(e => parseFloat(window.BorealisValueBus[e.source]) || 0).reduce((a, b) => a + b, 0);
|
||||
|
||||
const valA = sum(inputsA);
|
||||
const valB = sum(inputsB);
|
||||
|
||||
let value = 0;
|
||||
switch (operator) {
|
||||
case "Add":
|
||||
value = valA + valB;
|
||||
break;
|
||||
case "Subtract":
|
||||
value = valA - valB;
|
||||
break;
|
||||
case "Multiply":
|
||||
value = valA * valB;
|
||||
break;
|
||||
case "Divide":
|
||||
value = valB !== 0 ? valA / valB : 0;
|
||||
break;
|
||||
case "Average":
|
||||
const totalInputs = inputsA.length + inputsB.length;
|
||||
const totalSum = valA + valB;
|
||||
value = totalInputs > 0 ? totalSum / totalInputs : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
resultRef.current = value;
|
||||
setResult(value.toString());
|
||||
window.BorealisValueBus[id] = value.toString();
|
||||
|
||||
setNodes(nds =>
|
||||
nds.map(n =>
|
||||
n.id === id ? { ...n, data: { ...n.data, operator, value: value.toString() } } : n
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
intervalId = setInterval(runLogic, currentRate);
|
||||
|
||||
const monitor = setInterval(() => {
|
||||
const newRate = window.BorealisUpdateRate;
|
||||
if (newRate !== currentRate) {
|
||||
clearInterval(intervalId);
|
||||
currentRate = newRate;
|
||||
intervalId = setInterval(runLogic, currentRate);
|
||||
}
|
||||
}, 250);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
clearInterval(monitor);
|
||||
};
|
||||
}, [id, operator, edges, setNodes]);
|
||||
|
||||
return (
|
||||
<div className="borealis-node">
|
||||
<div style={{ position: "absolute", left: -16, top: 12, fontSize: "8px", color: "#ccc" }}>A</div>
|
||||
<div style={{ position: "absolute", left: -16, top: 50, fontSize: "8px", color: "#ccc" }}>B</div>
|
||||
<Handle type="target" position={Position.Left} id="a" style={{ top: 12 }} className="borealis-handle" />
|
||||
<Handle type="target" position={Position.Left} id="b" style={{ top: 50 }} className="borealis-handle" />
|
||||
|
||||
<div className="borealis-node-header">
|
||||
{data?.label || "Math Operation"}
|
||||
</div>
|
||||
|
||||
<div className="borealis-node-content">
|
||||
<div style={{ marginBottom: "8px", fontSize: "9px", color: "#ccc" }}>
|
||||
Aggregates A and B inputs then performs operation.
|
||||
</div>
|
||||
|
||||
<label style={{ fontSize: "9px", display: "block", marginBottom: "4px" }}>
|
||||
Operator:
|
||||
</label>
|
||||
<select
|
||||
value={operator}
|
||||
onChange={(e) => setOperator(e.target.value)}
|
||||
style={dropdownStyle}
|
||||
>
|
||||
<option value="Add">Add</option>
|
||||
<option value="Subtract">Subtract</option>
|
||||
<option value="Multiply">Multiply</option>
|
||||
<option value="Divide">Divide</option>
|
||||
<option value="Average">Average</option>
|
||||
</select>
|
||||
|
||||
<label style={{ fontSize: "9px", display: "block", marginBottom: "4px" }}>
|
||||
Result:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={result}
|
||||
disabled
|
||||
style={resultBoxStyle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Handle type="source" position={Position.Right} className="borealis-handle" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const dropdownStyle = {
|
||||
fontSize: "9px",
|
||||
padding: "4px",
|
||||
background: "#1e1e1e",
|
||||
color: "#ccc",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "2px",
|
||||
width: "100%",
|
||||
marginBottom: "8px"
|
||||
};
|
||||
|
||||
const resultBoxStyle = {
|
||||
fontSize: "9px",
|
||||
padding: "4px",
|
||||
background: "#2a2a2a",
|
||||
color: "#ccc",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "2px",
|
||||
width: "100%"
|
||||
};
|
||||
|
||||
export default {
|
||||
type: "MathNode",
|
||||
label: "Math Operation",
|
||||
description: `
|
||||
Perform Math on Aggregated Inputs
|
||||
|
||||
- A and B groups are independently summed
|
||||
- Performs: Add, Subtract, Multiply, Divide, or Average
|
||||
- Result = A <op> B
|
||||
- Emits result via BorealisValueBus every update tick
|
||||
`.trim(),
|
||||
content: "Perform Math Operations",
|
||||
component: MathNode
|
||||
};
|
119
Data/WebUI/src/nodes/Organization/Backdrop_Group_Box.jsx
Normal file
119
Data/WebUI/src/nodes/Organization/Backdrop_Group_Box.jsx
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* ===========================================
|
||||
* Borealis - Backdrop Group Box Node
|
||||
* ===========================================
|
||||
*
|
||||
* COMPONENT ROLE:
|
||||
* This node functions as a backdrop or grouping box.
|
||||
* It's resizable and can be renamed by clicking its title.
|
||||
* It doesn't connect to other nodes or pass data—it's purely visual.
|
||||
*
|
||||
* BEHAVIOR:
|
||||
* - Allows renaming via single-click on the header text.
|
||||
* - Can be resized by dragging from the bottom-right corner.
|
||||
*
|
||||
* NOTE:
|
||||
* - No inputs/outputs: purely cosmetic for grouping and labeling.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Handle, Position } from "reactflow";
|
||||
import { ResizableBox } from "react-resizable";
|
||||
import "react-resizable/css/styles.css";
|
||||
|
||||
const BackdropGroupBoxNode = ({ id, data }) => {
|
||||
const [title, setTitle] = useState(data?.label || "Backdrop Group Box");
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEditing && inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}, [isEditing]);
|
||||
|
||||
const handleTitleClick = () => {
|
||||
setIsEditing(true);
|
||||
};
|
||||
|
||||
const handleTitleChange = (e) => {
|
||||
const newTitle = e.target.value;
|
||||
setTitle(newTitle);
|
||||
window.BorealisValueBus[id] = newTitle;
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ pointerEvents: "auto", zIndex: -1 }}> {/* Prevent blocking other nodes */}
|
||||
<ResizableBox
|
||||
width={200}
|
||||
height={120}
|
||||
minConstraints={[120, 80]}
|
||||
maxConstraints={[600, 600]}
|
||||
resizeHandles={["se"]}
|
||||
style={{
|
||||
backgroundColor: "rgba(44, 44, 44, 0.5)",
|
||||
border: "1px solid #3a3a3a",
|
||||
borderRadius: "4px",
|
||||
boxShadow: "0 0 5px rgba(88, 166, 255, 0.15)",
|
||||
overflow: "hidden",
|
||||
position: "relative"
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()} // prevent drag on resize
|
||||
>
|
||||
<div
|
||||
onClick={handleTitleClick}
|
||||
style={{
|
||||
backgroundColor: "rgba(35, 35, 35, 0.5)",
|
||||
padding: "6px 10px",
|
||||
fontWeight: "bold",
|
||||
fontSize: "10px",
|
||||
cursor: "pointer",
|
||||
userSelect: "none"
|
||||
}}
|
||||
>
|
||||
{isEditing ? (
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={handleTitleChange}
|
||||
onBlur={handleBlur}
|
||||
style={{
|
||||
fontSize: "10px",
|
||||
padding: "2px",
|
||||
background: "#1e1e1e",
|
||||
color: "#ccc",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "2px",
|
||||
width: "100%"
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span>{title}</span>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ padding: "10px", fontSize: "9px", height: "100%" }}>
|
||||
{/* Empty space for grouping */}
|
||||
</div>
|
||||
</ResizableBox>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
type: "BackdropGroupBoxNode",
|
||||
label: "Backdrop Group Box",
|
||||
description: `
|
||||
Resizable Grouping Node
|
||||
|
||||
- Purely cosmetic, for grouping related nodes
|
||||
- Resizable by dragging bottom-right corner
|
||||
- Rename by clicking on title bar
|
||||
`.trim(),
|
||||
content: "Use as a visual group label",
|
||||
component: BackdropGroupBoxNode
|
||||
};
|
@ -110,7 +110,7 @@ Run-Step "Install Python Dependencies into Virtual Python Environment" {
|
||||
}
|
||||
|
||||
# ---------------------- Build React App ----------------------
|
||||
Run-Step "Install NPM into ReactJS App" {
|
||||
Run-Step "ReactJS App: Install NPM" {
|
||||
$packageJsonPath = Join-Path $webUIDestination "package.json"
|
||||
if (Test-Path $packageJsonPath) {
|
||||
Push-Location $webUIDestination
|
||||
@ -120,20 +120,26 @@ Run-Step "Install NPM into ReactJS App" {
|
||||
}
|
||||
}
|
||||
|
||||
Run-Step "Install React Flow into ReactJS App" {
|
||||
Run-Step "ReactJS App: Install React Resizable" {
|
||||
Push-Location $webUIDestination
|
||||
npm install react-resizable --no-fund --audit=false | Out-Null
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Run-Step "ReactJS App: Install React Flow" {
|
||||
Push-Location $webUIDestination
|
||||
npm install reactflow --no-fund --audit=false | Out-Null
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Run-Step "Install Material UI Libraries into ReactJS App" {
|
||||
Run-Step "ReactJS App: Install Material UI Libraries" {
|
||||
Push-Location $webUIDestination
|
||||
$env:npm_config_loglevel = "silent" # Force NPM to be completely silent
|
||||
npm install --silent @mui/material @mui/icons-material @emotion/react @emotion/styled --no-fund --audit=false 2>&1 | Out-Null
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Run-Step "Build ReactJS App" {
|
||||
Run-Step "ReactJS App: Building App" {
|
||||
Push-Location $webUIDestination
|
||||
#npm run build | Out-Null
|
||||
npm run build
|
||||
|
Loading…
x
Reference in New Issue
Block a user