blob: 58c4d79c24304a771a7c1d7836460d341356a85e [file] [log] [blame]
gio3d0bf032025-06-05 06:57:26 +00001import React, { useMemo } from "react";
gio678746b2025-07-06 14:45:27 +00002import { useStateStore } from "@/lib/state";
gio3d0bf032025-06-05 06:57:26 +00003import { NodeDetails } from "./components/node-details";
4import { Actions } from "./components/actions";
gio678746b2025-07-06 14:45:27 +00005import { Canvas } from "./Canvas";
gio5fa66962025-06-13 09:30:40 +00006import { Separator } from "./components/ui/separator";
gio74c6f752025-07-05 04:10:58 +00007import { AppNode, NodeType } from "config";
gio5fa66962025-06-13 09:30:40 +00008
9const sections: { title: string; nodes: NodeType[] }[] = [
10 {
11 title: "Services",
12 nodes: ["app"],
13 },
14 {
15 title: "Databases",
16 nodes: ["postgresql", "mongodb"],
17 },
18 {
19 title: "File systems",
20 nodes: ["volume"],
21 },
22];
gioda120432025-06-02 09:42:26 +000023
24export function Overview(): React.ReactNode {
gio3d0bf032025-06-05 06:57:26 +000025 const store = useStateStore();
gio3fb133d2025-06-13 07:20:24 +000026 const nodes = useMemo(() => {
gio5fa66962025-06-13 09:30:40 +000027 return store.nodes.filter((n) => n.type !== "network" && n.type !== "github" && n.type !== undefined);
gio3fb133d2025-06-13 07:20:24 +000028 }, [store.nodes]);
gio5fa66962025-06-13 09:30:40 +000029 const groupedNodes = useMemo(() => {
30 return sections
31 .map((s) => ({
32 title: s.title,
33 nodes: nodes.filter((n) => s.nodes.includes(n.type)),
34 }))
35 .filter((s) => s.nodes.length > 0);
36 }, [nodes]);
gio3d0bf032025-06-05 06:57:26 +000037 const isDeployMode = useMemo(() => store.mode === "deploy", [store.mode]);
gioda120432025-06-02 09:42:26 +000038 return (
gio3d0bf032025-06-05 06:57:26 +000039 <div className="h-full w-full overflow-auto bg-white p-2">
40 <div className="w-full flex flex-row justify-end">
gio678746b2025-07-06 14:45:27 +000041 <Actions />
gio3d0bf032025-06-05 06:57:26 +000042 <Canvas className="hidden" />
gioda120432025-06-02 09:42:26 +000043 </div>
gio5fa66962025-06-13 09:30:40 +000044 <div className="flex flex-col gap-4 pt-2">
45 {groupedNodes.map((s, index) => (
46 <>
47 {index > 0 && <Separator />}
48 <Section key={s.title} title={s.title} nodes={s.nodes} isDeployMode={isDeployMode} />
49 </>
50 ))}
51 </div>
52 </div>
53 );
54}
55
56function Section({
57 title,
58 nodes,
59 isDeployMode,
60}: {
61 title: string;
62 nodes: AppNode[];
63 isDeployMode: boolean;
64}): React.ReactNode {
65 if (nodes.length === 0) return null;
66 return (
67 <div className="w-full">
68 <h2 className="text-lg font-semibold mb-2">{title}</h2>
69 <div className="flex flex-wrap gap-4 pl-4">
70 {nodes.map((n) => (
71 <NodeDetails
72 key={n.id}
73 node={n}
74 disabled={isDeployMode}
75 showName={true}
gioe7734b22025-06-13 10:12:04 +000076 isOverview={true}
gio5fa66962025-06-13 09:30:40 +000077 className="min-w-[500px] rounded-lg border-gray-200 border-2 p-2"
78 />
79 ))}
gioda120432025-06-02 09:42:26 +000080 </div>
gio3d0bf032025-06-05 06:57:26 +000081 </div>
gioda120432025-06-02 09:42:26 +000082 );
83}