import React from "react";
import { connect } from "react-redux";
import { FixedSizeList } from "react-window";
import SplitPane from "react-split-pane";
import { makeStyles, withStyles } from "@material-ui/core/styles";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import MuiAccordion from "@material-ui/core/Accordion";
import MuiAccordionSummary from "@material-ui/core/AccordionSummary";
import MuiAccordionDetails from "@material-ui/core/AccordionDetails";
import useResizeAware from "react-resize-aware";
import { getSelected } from "./redux/store";
import { selectedGraphPaths, setSelectedPath } from "./redux/graphPaths";
import { setGraphData } from "./redux/graphData";
import { setLinks } from "./redux/links";
import { setLinksTrans } from "./redux/linksTrans";
import OverflowTooltip from "./OverflowTooltip";
const rowHeight = 25;
const Accordion = withStyles({
root: {
border: "1px solid rgba(0, 0, 0, .125)",
boxShadow: "none",
"&:not(:last-child)": {
borderBottom: 0,
},
"&:before": {
display: "none",
},
"&$expanded": {
margin: "auto",
},
},
expanded: {},
})(MuiAccordion);
const AccordionSummary = withStyles({
root: {
backgroundColor: "rgba(0, 0, 0, .03)",
borderBottom: "1px solid rgba(0, 0, 0, .125)",
marginBottom: -1,
minHeight: 56,
"&$expanded": {
minHeight: 56,
},
},
content: {
"&$expanded": {
margin: "12px 0",
},
},
expanded: {},
})(MuiAccordionSummary);
const AccordionDetails = withStyles((theme) => ({
root: {
padding: theme.spacing(2),
},
}))(MuiAccordionDetails);
const GraphPaths = ({
nodes,
selectedGraph,
selectedNodes,
graphPaths,
setSelectedPath,
width,
selectedGraphPaths,
setGraphData,
setLinks,
setLinksTrans,
showTransitive,
transPathFrom,
transPathTo
}) => {
const [fromNode, setFromNode] = React.useState("");
const [toNode, setToNode] = React.useState("");
const [fromNodeId, setFromNodeId] = React.useState(0);
const [toNodeId, setToNodeId] = React.useState(0);
const [fromNodeExpanded, setFromNodeExpanded] = React.useState(false);
const [toNodeExpanded, setToNodeExpanded] = React.useState(false);
const [paneSize, setPaneSize] = React.useState("50%");
const [fromResizeListener, fromSizes] = useResizeAware();
const [toResizeListener, toSizes] = useResizeAware();
const useStyles = makeStyles((theme) => ({
root: {
width: "100%",
maxWidth: width,
backgroundColor: theme.palette.background.paper,
},
nested: {
paddingLeft: theme.spacing(4),
},
listItem: {
width: width,
},
}));
const classes = useStyles();
React.useEffect(() => {
setFromNode(transPathFrom);
setFromNodeExpanded(false);
setToNode(transPathFrom);
setToNodeExpanded(false);
setPaneSize("50%");
if (transPathFrom != '' && transPathTo != '') {
getGraphPaths(transPathFrom, transPathTo);
} else {
selectedGraphPaths({
fromNode: '',
toNode: '',
paths: [],
selectedPath: -1
});
}
}, [transPathFrom, transPathTo]);
function getGraphPaths(fromNode, toNode) {
let gitHash = selectedGraph;
if (gitHash) {
let postData = {
"fromNode": fromNode,
"toNode": toNode
};
fetch('/api/graphs/' + gitHash + '/paths', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then(response => response.json())
.then(data => {
selectedGraphPaths(data);
let postData = {
"selected_nodes": nodes.filter(node => node.selected == true).map(node => node.node),
"extra_nodes": data.extraNodes,
"transitive_edges": showTransitive
};
fetch('/api/graphs/' + gitHash + '/d3', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then(response => response.json())
.then(data => {
setGraphData(data.graphData);
setLinks(
data.graphData.links.map((link) => {
if (link.source == fromNode && link.target == toNode) {
link.selected = true;
} else {
link.selected = false;
}
return link;
})
);
setLinksTrans(data.graphData.links_trans);
});
});
}
}
function toNodeRow({ index, style, data }) {
return (
{
setToNode(data[index].name);
setToNodeId(index);
setToNodeExpanded(false);
setPaneSize("50%");
if (fromNode != "" && data[fromNodeId]) {
getGraphPaths(data[fromNodeId].node, data[index].node);
}
}}
>
);
}
function fromNodeRow({ index, style, data }) {
return (
{
setFromNode(data[index].name);
setFromNodeId(index);
setFromNodeExpanded(false);
setPaneSize("50%");
if (toNode != "" && data[toNodeId]) {
getGraphPaths(data[fromNodeId].node, data[index].node);
}
}}
>
);
}
function pathRow({ index, style, data }) {
return (
{
setSelectedPath(index);
}}
>
);
}
function listHeight(numItems, minHeight, maxHeight) {
const size = numItems * rowHeight;
if (size > maxHeight) {
return maxHeight;
}
if (size < minHeight) {
return minHeight;
}
return size;
}
const handleToChange = (panel) => (event, newExpanded) => {
setPaneSize(newExpanded ? "0%" : "50%");
setToNodeExpanded(newExpanded ? panel : false);
};
const handleFromChange = (panel) => (event, newExpanded) => {
setPaneSize(newExpanded ? "100%" : "50%");
setFromNodeExpanded(newExpanded ? panel : false);
};
return (
}
aria-controls="panel1a-content"
id="panel1a-header"
>
From Node:
{fromResizeListener}
{fromNode}
{fromNodeRow}
}
aria-controls="panel1a-content"
id="panel1a-header"
>
To Node:
{toResizeListener}
{toNode}
{toNodeRow}
Num Paths: {graphPaths.paths.length}{" "}
{pathRow}
);
};
export default connect(getSelected, { selectedGraphPaths, setSelectedPath, setGraphData, setLinks, setLinksTrans })(
GraphPaths
);