Canvas: Rework Deployment/Gateways tab
Change-Id: I938262b9a6ba2af060531e7dcdf91ddd66721385
diff --git a/apps/canvas/front/src/Gateways.tsx b/apps/canvas/front/src/Gateways.tsx
new file mode 100644
index 0000000..a1fce28
--- /dev/null
+++ b/apps/canvas/front/src/Gateways.tsx
@@ -0,0 +1,93 @@
+import { z } from "zod";
+import { accessSchema, useEnv } from "./lib/state";
+import { Copy, Globe, Terminal, Network, Database, Check } from "lucide-react";
+import { Button } from "./components/ui/button";
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./components/ui/tooltip";
+import { useCallback, useState } from "react";
+
+export function Gateways() {
+ const env = useEnv();
+ const groupedAccess = env.access.reduce((acc, curr) => {
+ if (!acc.has(curr.name)) {
+ acc.set(curr.name, []);
+ }
+ acc.get(curr.name)!.push(curr);
+ return acc;
+ }, new Map<string, typeof env.access>());
+ return (
+ <ul>
+ {Array.from(groupedAccess.entries()).map(([name, access]) => (
+ <li key={name}>
+ {access.map((a) => (
+ <Gateway g={a} />
+ ))}
+ </li>
+ ))}
+ </ul>
+ );
+}
+
+function Gateway({ g }: { g: z.infer<typeof accessSchema> }) {
+ const [hidden, content] = (() => {
+ switch (g.type) {
+ case "https":
+ return [g.address, g.address];
+ case "ssh":
+ case "tcp":
+ case "udp":
+ return [`${g.host}:${g.port}`, `${g.host}:${g.port}`];
+ case "postgresql":
+ return [
+ `postgresql://${g.username}:*****@${g.host}:${g.port}/${g.database}`,
+ `postgresql://${g.username}:${g.password}@${g.host}:${g.port}/${g.database}`,
+ ];
+ case "mongodb":
+ return [
+ `mongodb://${g.username}:*****@${g.host}:${g.port}/${g.database}`,
+ `mongodb://${g.username}:${g.password}@${g.host}:${g.port}/${g.database}`,
+ ];
+ }
+ })();
+ const [clicked, setClicked] = useState(false);
+ const [open, setOpen] = useState(false);
+ const copy = useCallback(() => {
+ navigator.clipboard.writeText(content);
+ setClicked(true);
+ setOpen(true);
+ setTimeout(() => {
+ setClicked(false);
+ setOpen(false);
+ }, 1000);
+ }, [content, setClicked, setOpen]);
+ return (
+ <TooltipProvider>
+ <Tooltip delayDuration={100} open={open} onOpenChange={setOpen}>
+ <TooltipTrigger asChild>
+ <Button variant="ghost" onClick={copy}>
+ <AccessType type={g.type} className="w-4 h-4" />
+ <div className="hover:bg-gray-200 p-x-1">{hidden}</div>
+ </Button>
+ </TooltipTrigger>
+ <TooltipContent side="right" className="!bg-transparent cursor-pointer !p-0" sideOffset={1}>
+ {!clicked && <Copy className="w-4 h-4 !bg-transparent" color="black" />}
+ {clicked && <Check className="w-4 h-4 !bg-transparent" color="black" />}
+ </TooltipContent>
+ </Tooltip>
+ </TooltipProvider>
+ );
+}
+
+function AccessType({ type, className }: { type: z.infer<typeof accessSchema>["type"]; className?: string }) {
+ switch (type) {
+ case "https":
+ return <Globe className={className} />;
+ case "ssh":
+ return <Terminal className={className} />;
+ case "tcp":
+ case "udp":
+ return <Network className={className} />;
+ case "postgresql":
+ case "mongodb":
+ return <Database className={className} />;
+ }
+}