blob: 0d6bdf43066c4ae74d99511495695d2aaee0f431 [file] [log] [blame]
giob77cb932025-05-19 09:37:14 +00001import { z } from "zod";
2import { accessSchema, useEnv } from "./lib/state";
3import { Copy, Globe, Terminal, Network, Database, Check } from "lucide-react";
4import { Button } from "./components/ui/button";
5import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./components/ui/tooltip";
6import { useCallback, useState } from "react";
7
8export function Gateways() {
9 const env = useEnv();
10 const groupedAccess = env.access.reduce((acc, curr) => {
11 if (!acc.has(curr.name)) {
12 acc.set(curr.name, []);
13 }
14 acc.get(curr.name)!.push(curr);
15 return acc;
16 }, new Map<string, typeof env.access>());
17 return (
18 <ul>
19 {Array.from(groupedAccess.entries()).map(([name, access]) => (
gio40370782025-05-19 11:04:52 +000020 <>
giob77cb932025-05-19 09:37:14 +000021 {access.map((a) => (
gio40370782025-05-19 11:04:52 +000022 <li key={name}>
23 <Gateway g={a} />
24 </li>
giob77cb932025-05-19 09:37:14 +000025 ))}
gio40370782025-05-19 11:04:52 +000026 </>
giob77cb932025-05-19 09:37:14 +000027 ))}
28 </ul>
29 );
30}
31
32function Gateway({ g }: { g: z.infer<typeof accessSchema> }) {
33 const [hidden, content] = (() => {
34 switch (g.type) {
35 case "https":
36 return [g.address, g.address];
37 case "ssh":
38 case "tcp":
39 case "udp":
40 return [`${g.host}:${g.port}`, `${g.host}:${g.port}`];
41 case "postgresql":
42 return [
43 `postgresql://${g.username}:*****@${g.host}:${g.port}/${g.database}`,
44 `postgresql://${g.username}:${g.password}@${g.host}:${g.port}/${g.database}`,
45 ];
46 case "mongodb":
47 return [
48 `mongodb://${g.username}:*****@${g.host}:${g.port}/${g.database}`,
49 `mongodb://${g.username}:${g.password}@${g.host}:${g.port}/${g.database}`,
50 ];
51 }
52 })();
53 const [clicked, setClicked] = useState(false);
54 const [open, setOpen] = useState(false);
55 const copy = useCallback(() => {
56 navigator.clipboard.writeText(content);
57 setClicked(true);
58 setOpen(true);
59 setTimeout(() => {
60 setClicked(false);
61 setOpen(false);
62 }, 1000);
63 }, [content, setClicked, setOpen]);
64 return (
65 <TooltipProvider>
66 <Tooltip delayDuration={100} open={open} onOpenChange={setOpen}>
67 <TooltipTrigger asChild>
gio6d8b71c2025-05-19 12:57:35 +000068 <Button
69 variant="ghost"
70 onClick={g.type === "https" ? () => window.open(content, "_blank") : copy}
71 className="!gap-1 !p-0 !h-fit"
72 >
giob77cb932025-05-19 09:37:14 +000073 <AccessType type={g.type} className="w-4 h-4" />
74 <div className="hover:bg-gray-200 p-x-1">{hidden}</div>
75 </Button>
76 </TooltipTrigger>
gio05a993c2025-05-19 11:51:33 +000077 <TooltipContent side="right" className="!bg-transparent cursor-pointer !p-0" sideOffset={10}>
giob77cb932025-05-19 09:37:14 +000078 {!clicked && <Copy className="w-4 h-4 !bg-transparent" color="black" />}
79 {clicked && <Check className="w-4 h-4 !bg-transparent" color="black" />}
80 </TooltipContent>
81 </Tooltip>
82 </TooltipProvider>
83 );
84}
85
86function AccessType({ type, className }: { type: z.infer<typeof accessSchema>["type"]; className?: string }) {
87 switch (type) {
88 case "https":
89 return <Globe className={className} />;
90 case "ssh":
91 return <Terminal className={className} />;
92 case "tcp":
93 case "udp":
94 return <Network className={className} />;
95 case "postgresql":
96 case "mongodb":
97 return <Database className={className} />;
98 }
99}