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