diff --git a/ui100/src/EnvironmentNode.tsx b/ui100/src/EnvironmentNode.tsx
index 112dfe727..fcc8f42a1 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 a6ad2295f..64434cd29 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<MRT_RowSelectionState>({});
+
+    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<MRT_ColumnDef<Node>[]>(
         () => [
@@ -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 (
         <Box sx={{ width: "100%", mt: 2 }} height={{ xs: 400, sm: 600, md: 800 }}>
             <Paper>
diff --git a/ui100/src/Visualizer.tsx b/ui100/src/Visualizer.tsx
index 0d0aa8beb..db14a8d1c 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 (
         <ReactFlow
             nodeTypes={nodeTypes}
             nodes={nodes}
-            edges={edges}
             onNodesChange={onNodesChange}
-            onEdgesChange={onEdgesChange}
+            edges={edges}
             onSelectionChange={onSelectionChange}
             nodesDraggable={false}
-            defaultViewport={defaultViewport}
+            defaultViewport={viewport}
+            fitView={fitView}
         >
             <Background  />
             <Controls position="bottom-left" orientation="horizontal" showInteractive={false} />
diff --git a/ui100/src/model/store.ts b/ui100/src/model/store.ts
index e04beab47..950f1d854 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<Environment>;
     overview: VisualOverview;
+    environments: Array<Environment>;
+    nodes: Node[];
+    edges: Edge[];
     selectedNode: Node;
-    viewport: Array<Number>;
+    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<StoreState & StoreAction>((set) => ({
     user: null,
     overview: new VisualOverview(),
     environments: new Array<Environment>(),
+    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})
 }));