Canvas: Add new nodes at random positions

Change-Id: I17ba195065bf8c2f7d1eea2091793766f0e0ac65
diff --git a/apps/canvas/front/src/components/canvas.tsx b/apps/canvas/front/src/components/canvas.tsx
index 8ab4aaa..252c1b9 100644
--- a/apps/canvas/front/src/components/canvas.tsx
+++ b/apps/canvas/front/src/components/canvas.tsx
@@ -8,8 +8,9 @@
 	Edge,
 	useReactFlow,
 	Panel,
+	useStoreApi,
 } from "@xyflow/react";
-import { useStateStore, AppState, AppNode, useEnv } from "@/lib/state";
+import { useStateStore, AppState, AppNode } from "@/lib/state";
 import { useShallow } from "zustand/react/shallow";
 import { useCallback, useEffect, useMemo } from "react";
 import { NodeGatewayHttps } from "@/components/node-gateway-https";
@@ -33,7 +34,17 @@
 export function Canvas() {
 	const { nodes, edges, onNodesChange, onEdgesChange, onConnect } = useStateStore(useShallow(selector));
 	const store = useStateStore();
-	const flow = useReactFlow();
+	const instance = useReactFlow();
+	const flow = useStoreApi();
+	useEffect(() => {
+		store.setViewport({
+			width: flow.getState().width,
+			height: flow.getState().height,
+			transformX: flow.getState().transform[0],
+			transformY: flow.getState().transform[1],
+			transformZoom: flow.getState().transform[2],
+		});
+	}, [store, flow]);
 	const nodeTypes = useMemo(
 		() => ({
 			network: NodeNetwork,
@@ -52,8 +63,8 @@
 			if (c.source === c.target) {
 				return false;
 			}
-			const sn = flow.getNode(c.source)! as AppNode;
-			const tn = flow.getNode(c.target)! as AppNode;
+			const sn = instance.getNode(c.source)! as AppNode;
+			const tn = instance.getNode(c.target)! as AppNode;
 			if (sn.type === "github") {
 				return c.targetHandle === "repository";
 			}
@@ -83,33 +94,8 @@
 			}
 			return true;
 		},
-		[flow],
+		[instance],
 	);
-	const env = useEnv();
-	useEffect(() => {
-		const networkNodes: AppNode[] = env.networks.map((n) => ({
-			id: n.domain,
-			type: "network",
-			position: {
-				x: 0,
-				y: 0,
-			},
-			isConnectable: true,
-			data: {
-				domain: n.domain,
-				label: n.domain,
-				envVars: [],
-				ports: [],
-				state: "success", // TODO(gio): monitor network health
-			},
-		}));
-		const prevNodes = store.nodes;
-		const newNodes = networkNodes.concat(prevNodes.filter((n) => n.type !== "network"));
-		// TODO(gio): actually compare
-		if (prevNodes.length !== newNodes.length) {
-			store.setNodes(newNodes);
-		}
-	}, [env, store]);
 	return (
 		<div style={{ width: "100%", height: "100%" }}>
 			<ReactFlow