Canvas: build application infrastructure with drag and drop

Change-Id: I5cfd12e67794f3376c5c025af29470d52d77cf16
diff --git a/apps/canvas/src/Deployment.tsx b/apps/canvas/src/Deployment.tsx
new file mode 100644
index 0000000..2864a2a
--- /dev/null
+++ b/apps/canvas/src/Deployment.tsx
@@ -0,0 +1,55 @@
+import { useNodes } from "@xyflow/react";
+import { AppNode, nodeLabel, ServiceNode } from "./lib/state";
+import { useMemo } from "react";
+import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "./components/ui/table";
+
+function ingress(nodes: AppNode[]) {
+    const nm = new Map(nodes.map((n) => [n.id, n]));
+    return nodes.filter((n) => n.type === "gateway-https").map((i) => {
+        console.log(i.data);
+        if (!i.data || !i.data.network || !i.data.subdomain) {
+            return null;
+        }
+        if (!i.data.https || !i.data.https.serviceId || !i.data.https.portId) {
+            return null;
+        }
+        console.log("1231");
+        const svc = nm.get(i.data.https.serviceId)! as ServiceNode;
+        const port = svc.data.ports.find((p) => p.id === i.data.https!.portId)!;
+        console.log({svc, port});
+        return {
+            id: `${i.id} - ${port.id}`,
+            service: svc,
+            port: port,
+            endpoint: `https://${i.data.subdomain}.${i.data.network}`,
+        };
+    }).filter((i) => i != null);
+}
+
+export function Deployment() {
+    const nodes = useNodes<AppNode>();
+    const ing = useMemo(() => ingress(nodes), [nodes]);
+    return (
+        <>
+            <Table>
+                <TableCaption>HTTPS Gateways</TableCaption>
+                <TableHeader>
+                    <TableRow>
+                        <TableHead>Service</TableHead>
+                        <TableHead>Port</TableHead>
+                        <TableHead>Endpoint</TableHead>
+                    </TableRow>
+                </TableHeader>
+                <TableBody>
+                    {ing.map((i) => (
+                        <TableRow>
+                            <TableCell>{nodeLabel(i.service)}</TableCell>
+                            <TableCell>{i.port.name}</TableCell>
+                            <TableCell><a href={i.endpoint} target="_blank">{i.endpoint}</a></TableCell>                           
+                        </TableRow>
+                    ))}
+                </TableBody>
+            </Table>
+        </>
+    );
+}
\ No newline at end of file