From c22b20f11206855eca31657ad3ebb6bd2c6057c1 Mon Sep 17 00:00:00 2001 From: Jason Madigan Date: Wed, 21 Aug 2024 15:41:35 +0100 Subject: [PATCH] component-ize things further --- package.json | 2 +- src/App.css | 15 +++++ src/App.js | 77 ++++++++++++++++++++- src/DotStringEditor.js | 49 ++++++++++++++ src/PickResource.js | 45 +++++++++++++ src/PolicyTopology.js | 133 +++---------------------------------- src/ResetPolicyTopology.js | 12 ++++ 7 files changed, 205 insertions(+), 128 deletions(-) create mode 100644 src/DotStringEditor.js create mode 100644 src/PickResource.js create mode 100644 src/ResetPolicyTopology.js diff --git a/package.json b/package.json index e280cbb..5853640 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-policy-topology", - "version": "0.1.1", + "version": "0.1.2", "type": "module", "dependencies": { "@patternfly/patternfly": "^4.224.5", diff --git a/src/App.css b/src/App.css index a02b8d3..4ac8ad7 100644 --- a/src/App.css +++ b/src/App.css @@ -48,3 +48,18 @@ transform: rotate(360deg); } } + +.dot-string-editor { + margin-top: 20px; + max-width: 1000px; /* Increase the max-width to make the textarea wider */ + width: 100%; /* Ensure the textarea takes the full width available */ +} + +.dot-string-editor h3 { + margin-bottom: 10px; +} + +.large-textarea { + width: 100%; /* Ensure the textarea takes the full width of its container */ + font-size: 14px; /* Optional: Adjust the font size */ +} diff --git a/src/App.js b/src/App.js index 29c1bb7..f4afbaa 100644 --- a/src/App.js +++ b/src/App.js @@ -1,9 +1,14 @@ -import React from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import PolicyTopology from './PolicyTopology.js'; +import PickResource from './PickResource.js'; +import ResetPolicyTopology from './ResetPolicyTopology.js'; +import DotStringEditor from './DotStringEditor.js'; // Import the new component +import graphlib from 'graphlib'; +import * as dot from 'graphlib-dot'; import './App.css'; function App() { - const dotString = ` + const initialDotString = ` strict digraph "" { graph [bb="0,0,440.51,352"]; node [fillcolor=lightgrey, @@ -112,11 +117,77 @@ function App() { } `; + const [dotString, setDotString] = useState(initialDotString); + const [filteredDot, setFilteredDot] = useState(dotString); + const [graph, setGraph] = useState(null); + + useEffect(() => { + const g = dot.read(dotString); + setGraph(g); + setFilteredDot(dotString); + }, [dotString]); + + const handleNodeSelection = useCallback((nodeId) => { + if (!graph) return; + + if (nodeId === null) { + setFilteredDot(dotString); + return; + } + + const filteredGraph = new graphlib.Graph(); + const nodesToInclude = new Set(); + + const addPredecessors = (node) => { + if (!nodesToInclude.has(node)) { + nodesToInclude.add(node); + const predecessors = graph.predecessors(node) || []; + predecessors.forEach(addPredecessors); + } + }; + + const addSuccessors = (node) => { + const successors = graph.successors(node) || []; + successors.forEach(successor => { + nodesToInclude.add(successor); + }); + }; + + addPredecessors(nodeId); + addSuccessors(nodeId); + + nodesToInclude.forEach(node => { + filteredGraph.setNode(node, graph.node(node)); + }); + + graph.edges().forEach(edge => { + if (nodesToInclude.has(edge.v) && nodesToInclude.has(edge.w)) { + filteredGraph.setEdge(edge.v, edge.w, graph.edge(edge.v, edge.w)); + } + }); + + const filteredDotString = dot.write(filteredGraph); + setFilteredDot(filteredDotString); + }, [graph, dotString]); + + const resetGraph = () => { + setFilteredDot(dotString); + }; + + const handleDotStringChange = (newDotString) => { + setDotString(newDotString); + }; + return (

Policy Topology Example

- +
+ + +
+ +
); diff --git a/src/DotStringEditor.js b/src/DotStringEditor.js new file mode 100644 index 0000000..6550d79 --- /dev/null +++ b/src/DotStringEditor.js @@ -0,0 +1,49 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { TextArea } from '@patternfly/react-core'; + +const DotStringEditor = ({ dotString, onDotStringChange }) => { + const [localDotString, setLocalDotString] = useState(dotString); + const timeoutRef = useRef(null); + + useEffect(() => { + setLocalDotString(dotString); + }, [dotString]); + + const handleChange = (value) => { + setLocalDotString(value); + + // Clear the existing timeout if there is one + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + // Set a new timeout to trigger the update after 1 second of inactivity + timeoutRef.current = setTimeout(() => { + onDotStringChange(value); + }, 1000); // 1 second delay + }; + + // Clear the timeout on component unmount + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, []); + + return ( +
+

Edit DOT String

+