Skip to content

Commit

Permalink
Add filtering to PolicyTopology itself. 0.1.6
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Madigan <[email protected]>
  • Loading branch information
jasonmadigan committed Aug 22, 2024
1 parent b912f38 commit a2754f1
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 67 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-policy-topology",
"version": "0.1.5",
"version": "0.1.6",
"type": "module",
"main": "src/main.js",
"module": "src/main.js",
Expand Down
64 changes: 4 additions & 60 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect } from 'react';
import PolicyTopology from './PolicyTopology.js';
import PickResource from './PickResource.js';
import ResetPolicyTopology from './ResetPolicyTopology.js';
import DotStringEditor from './DotStringEditor.js';
import graphlib from 'graphlib';
import * as dot from 'graphlib-dot';
import * as dot from 'graphlib-dot'; // still needed for parsing dotString
import './App.css';

function App() {
Expand Down Expand Up @@ -125,67 +122,14 @@ function App() {
setGraph(g);
}, [dotString]);

const handleNodeSelection = useCallback((nodeId) => {
if (!graph) return;

if (nodeId === null) {
setDotString(initialDotString);
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);
setDotString(filteredDotString);
}, [graph, initialDotString]);

const resetGraph = () => {
setDotString(initialDotString);
};

const handleDotStringChange = (newDotString) => {
setDotString(newDotString);
};

return (
<div className="App">
<header className="App-header">
<h1>Policy Topology Example</h1>
<div className="controls-container">
<PickResource graph={graph} onResourceSelect={handleNodeSelection} />
<ResetPolicyTopology onReset={resetGraph} />
<PickResource graph={graph} onResourceSelect={(nodeId) => {}} />
</div>
<PolicyTopology dotString={dotString} onNodeClick={handleNodeSelection} />
<DotStringEditor dotString={dotString} onDotStringChange={handleDotStringChange} />
<PolicyTopology initialDotString={dotString} />
</header>
</div>
);
Expand Down
77 changes: 71 additions & 6 deletions src/PolicyTopology.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,66 @@
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, useState, useCallback } from 'react';
import * as d3 from 'd3';
import { graphviz } from 'd3-graphviz'; // eslint-disable-line no-unused-vars
import { Button } from '@patternfly/react-core';
import graphlib from 'graphlib';
import * as dot from 'graphlib-dot';
import './PolicyTopology.css';

const PolicyTopology = ({ dotString, onNodeClick }) => {
const PolicyTopology = ({ initialDotString }) => {
const containerRef = useRef(null);
const [dotString, setDotString] = useState(initialDotString); // State for the dot string
const [graph, setGraph] = useState(null);

// Parse the DOT string into a graph object
useEffect(() => {
if (containerRef.current && dotString) {
if (dotString) {
const g = dot.read(dotString);
setGraph(g);
}
}, [dotString]);

// Function to handle node selection and update the graph
const handleNodeSelection = useCallback((nodeId) => {
if (!graph) 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);
setDotString(filteredDotString); // Update the dotString state
}, [graph]);

// Render the graph when the component mounts or the dotString changes
useEffect(() => {
if (containerRef.current && graph) {
const renderGraph = () => {
d3.select(containerRef.current).graphviz()
.zoom(false)
Expand All @@ -19,17 +72,29 @@ const PolicyTopology = ({ dotString, onNodeClick }) => {
node.addEventListener('click', (event) => {
const nodeElement = event.target.closest('g.node');
const nodeId = nodeElement.querySelector('title').textContent;
onNodeClick(nodeId);
handleNodeSelection(nodeId);
});
});
});
};

renderGraph();
}
}, [dotString, onNodeClick]);
}, [graph, dotString, handleNodeSelection]);

// Function to reset the graph to its initial state
const resetGraph = useCallback(() => {
setDotString(initialDotString); // Reset the dotString state
}, [initialDotString]);

return <div ref={containerRef} className="policy-topology-container" />;
return (
<div>
<div className="policy-topology-container" ref={containerRef} />
<Button variant="secondary" onClick={resetGraph} style={{ marginTop: '10px' }}>
Reset Graph
</Button>
</div>
);
};

export default PolicyTopology;

0 comments on commit a2754f1

Please sign in to comment.