Skip to content

Commit deb0d8c

Browse files
selection and state management between the visualizer and tabular view (#804, #819, #823)
1 parent 0c551c8 commit deb0d8c

File tree

4 files changed

+82
-32
lines changed

4 files changed

+82
-32
lines changed

ui100/src/EnvironmentNode.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ const EnvironmentNode = ({ data }) => {
2727
s[i] = v;
2828
});
2929
setSparkData(s);
30-
} else {
31-
console.log("not found", data, environments);
3230
}
3331
}
3432
}, [environments]);

ui100/src/TabularView.tsx

+41-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
11
import {Box, Paper} from "@mui/material";
22
import useStore from "./model/store.ts";
3-
import {MaterialReactTable, type MRT_ColumnDef, useMaterialReactTable} from "material-react-table";
4-
import {useMemo} from "react";
3+
import {
4+
getMRT_RowSelectionHandler,
5+
MaterialReactTable,
6+
type MRT_ColumnDef,
7+
MRT_RowSelectionState,
8+
useMaterialReactTable
9+
} from "material-react-table";
10+
import {useEffect, useMemo, useState} from "react";
511
import {Node} from "@xyflow/react";
612

7-
const data: Node[] = [];
8-
913
const TabularView = () => {
10-
const overview = useStore((state) => state.overview);
14+
const nodes = useStore((state) => state.nodes);
15+
const selectedNode = useStore((state) => state.selectedNode);
16+
const updateSelectedNode = useStore((state) => state.updateSelectedNode);
17+
const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({});
18+
19+
useEffect(() => {
20+
if(selectedNode) {
21+
let selection = {};
22+
selection[selectedNode.id] = true;
23+
setRowSelection(selection);
24+
}
25+
}, []);
26+
27+
useEffect(() => {
28+
let sn = nodes.find(node => Object.keys(rowSelection).includes(node.id));
29+
updateSelectedNode(sn);
30+
}, [rowSelection]);
1131

1232
const columns = useMemo<MRT_ColumnDef<Node>[]>(
1333
() => [
@@ -25,11 +45,24 @@ const TabularView = () => {
2545

2646
const table = useMaterialReactTable({
2747
columns: columns,
28-
data: overview.nodes,
48+
data: nodes,
49+
enableRowSelection: false,
50+
enableMultiRowSelection: false,
51+
getRowId: r => r.id,
52+
onRowSelectionChange: setRowSelection,
53+
state: { rowSelection },
54+
muiTableBodyRowProps: ({ row }) => ({
55+
onClick: () => {
56+
setRowSelection({[row.id]: true})
57+
},
58+
selected: rowSelection[row.id],
59+
sx: {
60+
cursor: 'pointer',
61+
},
62+
}),
63+
positionToolbarAlertBanner: "bottom",
2964
});
3065

31-
console.log(overview.nodes);
32-
3366
return (
3467
<Box sx={{ width: "100%", mt: 2 }} height={{ xs: 400, sm: 600, md: 800 }}>
3568
<Paper>

ui100/src/Visualizer.tsx

+29-18
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import "@xyflow/react/dist/style.css";
22
import "./styling/react-flow.css";
33
import {
4+
applyNodeChanges,
45
Background,
56
Controls,
67
MiniMap,
78
Node,
89
ReactFlow,
910
ReactFlowProvider,
10-
useEdgesState,
11-
useNodesState,
12-
useStore as xyStore
11+
useOnViewportChange,
12+
Viewport
1313
} from "@xyflow/react";
1414
import {VisualOverview} from "./model/visualizer.ts";
1515
import {useEffect} from "react";
@@ -30,16 +30,24 @@ const nodeTypes = {
3030

3131
const Visualizer = () => {
3232
const overview = useStore((state) => state.overview);
33+
const selectedNode = useStore((state) => state.selectedNode);
3334
const updateSelectedNode = useStore((state) => state.updateSelectedNode);
3435
const viewport = useStore((state) => state.viewport);
3536
const updateViewport = useStore((state) => state.updateViewport);
36-
const [nodes, setNodes, onNodesChange] = useNodesState([]);
37-
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
38-
const transform = xyStore((store) => store.transform);
37+
const nodes = useStore((state) => state.nodes);
38+
const updateNodes = useStore((state) => state.updateNodes);
39+
const edges = useStore((state) => state.edges);
40+
const updateEdges = useStore((state) => state.updateEdges);
3941

40-
useEffect(() => {
41-
updateViewport(transform);
42-
}, [transform]);
42+
const onNodesChange = (changes) => {
43+
updateNodes(applyNodeChanges(changes, nodes));
44+
}
45+
46+
useOnViewportChange({
47+
onEnd: (viewport: Viewport) => {
48+
updateViewport(viewport);
49+
}
50+
});
4351

4452
const onSelectionChange = ({ nodes }) => {
4553
if(nodes.length > 0) {
@@ -80,27 +88,30 @@ const Visualizer = () => {
8088
useEffect(() => {
8189
if(overview) {
8290
let laidOut = layout(overview.nodes, overview.edges);
83-
setNodes(laidOut.nodes);
84-
setEdges(laidOut.edges);
91+
let selected = laidOut.nodes.map((n) => ({
92+
...n,
93+
selected: selectedNode ? selectedNode.id === n.id : false,
94+
}));
95+
updateNodes(selected);
96+
updateEdges(laidOut.edges);
8597
}
8698
}, [overview]);
8799

88-
const defaultViewport = {
89-
x: viewport[0],
90-
y: viewport[1],
91-
zoom: viewport[2],
100+
let fitView = false;
101+
if(viewport.x === 0 && viewport.y === 0 && viewport.zoom === 1) {
102+
fitView = true;
92103
}
93104

94105
return (
95106
<ReactFlow
96107
nodeTypes={nodeTypes}
97108
nodes={nodes}
98-
edges={edges}
99109
onNodesChange={onNodesChange}
100-
onEdgesChange={onEdgesChange}
110+
edges={edges}
101111
onSelectionChange={onSelectionChange}
102112
nodesDraggable={false}
103-
defaultViewport={defaultViewport}
113+
defaultViewport={viewport}
114+
fitView={fitView}
104115
>
105116
<Background />
106117
<Controls position="bottom-left" orientation="horizontal" showInteractive={false} />

ui100/src/model/store.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,42 @@
11
import {create} from "zustand";
22
import {Environment} from "../api";
33
import {VisualOverview} from "./visualizer.ts";
4-
import {Node} from "@xyflow/react";
4+
import {Edge, Node, Viewport} from "@xyflow/react";
55
import {User} from "./user.ts";
66

77
type StoreState = {
88
user: User;
9-
environments: Array<Environment>;
109
overview: VisualOverview;
10+
environments: Array<Environment>;
11+
nodes: Node[];
12+
edges: Edge[];
1113
selectedNode: Node;
12-
viewport: Array<Number>;
14+
viewport: Viewport;
1315
};
1416

1517
type StoreAction = {
1618
updateUser: (user: StoreState['user']) => void,
1719
updateOverview: (vov: StoreState['overview']) => void,
1820
updateEnvironments: (environments: StoreState['environments']) => void,
1921
updateSelectedNode: (selectedNode: StoreState['selectedNode']) => void,
22+
updateNodes: (nodes: StoreState['nodes']) => void,
23+
updateEdges: (edges: StoreState['edges']) => void,
2024
updateViewport: (viewport: StoreState['viewport']) => void,
2125
};
2226

2327
const useStore = create<StoreState & StoreAction>((set) => ({
2428
user: null,
2529
overview: new VisualOverview(),
2630
environments: new Array<Environment>(),
31+
nodes: [],
32+
edges: [],
2733
selectedNode: null,
28-
viewport: [0, 0, 1.5],
34+
viewport: {x: 0, y: 0, zoom: 1},
2935
updateUser: (user) => set({user: user}),
3036
updateOverview: (vov) => set({overview: vov}),
3137
updateEnvironments: (environments) => set({environments: environments}),
38+
updateNodes: (nodes) => set({nodes: nodes}),
39+
updateEdges: (edges) => set({edges: edges}),
3240
updateSelectedNode: (selectedNode) => set({selectedNode: selectedNode}),
3341
updateViewport: (viewport) => set({viewport: viewport})
3442
}));

0 commit comments

Comments
 (0)