From d3b3258dbf107351598a8489a67137cc185cda5d Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Mon, 5 May 2025 06:02:45 -0600 Subject: [PATCH] Added Text Upload & Display Nodes --- .../nodes/Data Analysis/Node_Regex_Search.jsx | 1 - .../Data Analysis/Node_TextArray_Display.jsx | 190 ++++++++++++++++++ .../Data Processing/Node_Upload_Text.jsx | 123 ++++++++++++ .../src/nodes/Templates/Node_Template.jsx | 10 - 4 files changed, 313 insertions(+), 11 deletions(-) create mode 100644 Data/Server/WebUI/src/nodes/Data Analysis/Node_TextArray_Display.jsx create mode 100644 Data/Server/WebUI/src/nodes/Data Processing/Node_Upload_Text.jsx diff --git a/Data/Server/WebUI/src/nodes/Data Analysis/Node_Regex_Search.jsx b/Data/Server/WebUI/src/nodes/Data Analysis/Node_Regex_Search.jsx index 10fd2d1..6fdf1db 100644 --- a/Data/Server/WebUI/src/nodes/Data Analysis/Node_Regex_Search.jsx +++ b/Data/Server/WebUI/src/nodes/Data Analysis/Node_Regex_Search.jsx @@ -1,5 +1,4 @@ ////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: /Data/WebUI/src/nodes/Data Analysis/Node_Regex_Search.jsx -////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: /Data/WebUI/src/nodes/Data Manipulation/Node_Regex_Search.jsx import React, { useEffect, useState, useRef } from "react"; import { Handle, Position, useReactFlow, useStore } from "reactflow"; diff --git a/Data/Server/WebUI/src/nodes/Data Analysis/Node_TextArray_Display.jsx b/Data/Server/WebUI/src/nodes/Data Analysis/Node_TextArray_Display.jsx new file mode 100644 index 0000000..ecab13e --- /dev/null +++ b/Data/Server/WebUI/src/nodes/Data Analysis/Node_TextArray_Display.jsx @@ -0,0 +1,190 @@ +////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: /nodes/Data Analysis/Node_TextArray_Display.jsx + +/** + * Display Multi-Line Array Node + * -------------------------------------------------- + * A node to display upstream multi-line text arrays. + * Has one input edge on left and passthrough output on right. + * Custom drag-resize handle for width & height adjustments. + * Inner textarea scrolls vertically; container overflow visible. + */ +import React, { useEffect, useState, useRef, useCallback } from "react"; +import { Handle, Position, useReactFlow, useStore } from "reactflow"; + +const TextArrayDisplayNode = ({ id, data }) => { + const { setNodes } = useReactFlow(); + const edges = useStore((state) => state.edges); + const containerRef = useRef(null); + const resizingRef = useRef(false); + const startPosRef = useRef({ x: 0, y: 0 }); + const startDimRef = useRef({ width: 0, height: 0 }); + + // Initialize lines and dimensions + const [lines, setLines] = useState(data?.lines || []); + const linesRef = useRef(lines); + const initW = parseInt(data?.width || "300", 10); + const initH = parseInt(data?.height || "150", 10); + const [dimensions, setDimensions] = useState({ width: initW, height: initH }); + + // Persist dimensions to node data + const persistDimensions = useCallback(() => { + const w = `${Math.round(dimensions.width)}px`; + const h = `${Math.round(dimensions.height)}px`; + setNodes((nds) => + nds.map((n) => + n.id === id + ? { ...n, data: { ...n.data, width: w, height: h } } + : n + ) + ); + }, [dimensions, id, setNodes]); + + // Mouse handlers for custom resize + useEffect(() => { + const onMouseMove = (e) => { + if (!resizingRef.current) return; + const dx = e.clientX - startPosRef.current.x; + const dy = e.clientY - startPosRef.current.y; + setDimensions({ + width: Math.max(100, startDimRef.current.width + dx), + height: Math.max(60, startDimRef.current.height + dy) + }); + }; + const onMouseUp = () => { + if (resizingRef.current) { + resizingRef.current = false; + persistDimensions(); + } + }; + window.addEventListener("mousemove", onMouseMove); + window.addEventListener("mouseup", onMouseUp); + return () => { + window.removeEventListener("mousemove", onMouseMove); + window.removeEventListener("mouseup", onMouseUp); + }; + }, [persistDimensions]); + + // Start drag + const onResizeMouseDown = (e) => { + e.stopPropagation(); + resizingRef.current = true; + startPosRef.current = { x: e.clientX, y: e.clientY }; + startDimRef.current = { ...dimensions }; + }; + + // Polling for upstream data + useEffect(() => { + let rate = window.BorealisUpdateRate; + const tick = () => { + const edge = edges.find((e) => e.target === id); + if (edge && edge.source) { + const arr = window.BorealisValueBus[edge.source] || []; + if (JSON.stringify(arr) !== JSON.stringify(linesRef.current)) { + linesRef.current = arr; + setLines(arr); + window.BorealisValueBus[id] = arr; + setNodes((nds) => + nds.map((n) => + n.id === id ? { ...n, data: { ...n.data, lines: arr } } : n + ) + ); + } + } else { + window.BorealisValueBus[id] = linesRef.current; + } + }; + const iv = setInterval(tick, rate); + const monitor = setInterval(() => { + if (window.BorealisUpdateRate !== rate) { + clearInterval(iv); + clearInterval(monitor); + } + }, 200); + return () => { clearInterval(iv); clearInterval(monitor); }; + }, [id, edges, setNodes]); + + return ( +
+ {/* Connectors */} + + + + {/* Header */} +
+ {data?.label || "Display Multi-Line Array"} +
+ + {/* Content */} +
+
+ {data?.content || "Display upstream multi-line text arrays."} +
+ +