diff --git a/ui100/src/EnvironmentNode.tsx b/ui100/src/EnvironmentNode.tsx index 112dfe72..fcc8f42a 100644 --- a/ui100/src/EnvironmentNode.tsx +++ b/ui100/src/EnvironmentNode.tsx @@ -27,8 +27,6 @@ const EnvironmentNode = ({ data }) => { s[i] = v; }); setSparkData(s); - } else { - console.log("not found", data, environments); } } }, [environments]); diff --git a/ui100/src/TabularView.tsx b/ui100/src/TabularView.tsx index a6ad2295..64434cd2 100644 --- a/ui100/src/TabularView.tsx +++ b/ui100/src/TabularView.tsx @@ -1,13 +1,33 @@ import {Box, Paper} from "@mui/material"; import useStore from "./model/store.ts"; -import {MaterialReactTable, type MRT_ColumnDef, useMaterialReactTable} from "material-react-table"; -import {useMemo} from "react"; +import { + getMRT_RowSelectionHandler, + MaterialReactTable, + type MRT_ColumnDef, + MRT_RowSelectionState, + useMaterialReactTable +} from "material-react-table"; +import {useEffect, useMemo, useState} from "react"; import {Node} from "@xyflow/react"; -const data: Node[] = []; - const TabularView = () => { - const overview = useStore((state) => state.overview); + const nodes = useStore((state) => state.nodes); + const selectedNode = useStore((state) => state.selectedNode); + const updateSelectedNode = useStore((state) => state.updateSelectedNode); + const [rowSelection, setRowSelection] = useState({}); + + useEffect(() => { + if(selectedNode) { + let selection = {}; + selection[selectedNode.id] = true; + setRowSelection(selection); + } + }, []); + + useEffect(() => { + let sn = nodes.find(node => Object.keys(rowSelection).includes(node.id)); + updateSelectedNode(sn); + }, [rowSelection]); const columns = useMemo[]>( () => [ @@ -25,11 +45,24 @@ const TabularView = () => { const table = useMaterialReactTable({ columns: columns, - data: overview.nodes, + data: nodes, + enableRowSelection: false, + enableMultiRowSelection: false, + getRowId: r => r.id, + onRowSelectionChange: setRowSelection, + state: { rowSelection }, + muiTableBodyRowProps: ({ row }) => ({ + onClick: () => { + setRowSelection({[row.id]: true}) + }, + selected: rowSelection[row.id], + sx: { + cursor: 'pointer', + }, + }), + positionToolbarAlertBanner: "bottom", }); - console.log(overview.nodes); - return ( diff --git a/ui100/src/Visualizer.tsx b/ui100/src/Visualizer.tsx index 0d0aa8be..db14a8d1 100644 --- a/ui100/src/Visualizer.tsx +++ b/ui100/src/Visualizer.tsx @@ -1,15 +1,15 @@ import "@xyflow/react/dist/style.css"; import "./styling/react-flow.css"; import { + applyNodeChanges, Background, Controls, MiniMap, Node, ReactFlow, ReactFlowProvider, - useEdgesState, - useNodesState, - useStore as xyStore + useOnViewportChange, + Viewport } from "@xyflow/react"; import {VisualOverview} from "./model/visualizer.ts"; import {useEffect} from "react"; @@ -30,16 +30,24 @@ const nodeTypes = { const Visualizer = () => { const overview = useStore((state) => state.overview); + const selectedNode = useStore((state) => state.selectedNode); const updateSelectedNode = useStore((state) => state.updateSelectedNode); const viewport = useStore((state) => state.viewport); const updateViewport = useStore((state) => state.updateViewport); - const [nodes, setNodes, onNodesChange] = useNodesState([]); - const [edges, setEdges, onEdgesChange] = useEdgesState([]); - const transform = xyStore((store) => store.transform); + const nodes = useStore((state) => state.nodes); + const updateNodes = useStore((state) => state.updateNodes); + const edges = useStore((state) => state.edges); + const updateEdges = useStore((state) => state.updateEdges); - useEffect(() => { - updateViewport(transform); - }, [transform]); + const onNodesChange = (changes) => { + updateNodes(applyNodeChanges(changes, nodes)); + } + + useOnViewportChange({ + onEnd: (viewport: Viewport) => { + updateViewport(viewport); + } + }); const onSelectionChange = ({ nodes }) => { if(nodes.length > 0) { @@ -80,27 +88,30 @@ const Visualizer = () => { useEffect(() => { if(overview) { let laidOut = layout(overview.nodes, overview.edges); - setNodes(laidOut.nodes); - setEdges(laidOut.edges); + let selected = laidOut.nodes.map((n) => ({ + ...n, + selected: selectedNode ? selectedNode.id === n.id : false, + })); + updateNodes(selected); + updateEdges(laidOut.edges); } }, [overview]); - const defaultViewport = { - x: viewport[0], - y: viewport[1], - zoom: viewport[2], + let fitView = false; + if(viewport.x === 0 && viewport.y === 0 && viewport.zoom === 1) { + fitView = true; } return ( diff --git a/ui100/src/model/store.ts b/ui100/src/model/store.ts index e04beab4..950f1d85 100644 --- a/ui100/src/model/store.ts +++ b/ui100/src/model/store.ts @@ -1,15 +1,17 @@ import {create} from "zustand"; import {Environment} from "../api"; import {VisualOverview} from "./visualizer.ts"; -import {Node} from "@xyflow/react"; +import {Edge, Node, Viewport} from "@xyflow/react"; import {User} from "./user.ts"; type StoreState = { user: User; - environments: Array; overview: VisualOverview; + environments: Array; + nodes: Node[]; + edges: Edge[]; selectedNode: Node; - viewport: Array; + viewport: Viewport; }; type StoreAction = { @@ -17,6 +19,8 @@ type StoreAction = { updateOverview: (vov: StoreState['overview']) => void, updateEnvironments: (environments: StoreState['environments']) => void, updateSelectedNode: (selectedNode: StoreState['selectedNode']) => void, + updateNodes: (nodes: StoreState['nodes']) => void, + updateEdges: (edges: StoreState['edges']) => void, updateViewport: (viewport: StoreState['viewport']) => void, }; @@ -24,11 +28,15 @@ const useStore = create((set) => ({ user: null, overview: new VisualOverview(), environments: new Array(), + nodes: [], + edges: [], selectedNode: null, - viewport: [0, 0, 1.5], + viewport: {x: 0, y: 0, zoom: 1}, updateUser: (user) => set({user: user}), updateOverview: (vov) => set({overview: vov}), updateEnvironments: (environments) => set({environments: environments}), + updateNodes: (nodes) => set({nodes: nodes}), + updateEdges: (edges) => set({edges: edges}), updateSelectedNode: (selectedNode) => set({selectedNode: selectedNode}), updateViewport: (viewport) => set({viewport: viewport}) }));