| import { useNodes } from "@xyflow/react"; |
| import { AppNode, nodeLabel, NodeType, useMode } from "@/lib/state"; |
| import { NodeDetails } from "@/components/node-details"; |
| import { Accordion, AccordionContent, AccordionTrigger } from "./ui/accordion"; |
| import { AccordionItem } from "@radix-ui/react-accordion"; |
| import { useMemo, useState } from "react"; |
| import { Icon } from "./icon"; |
| import { Separator } from "./ui/separator"; |
| |
| function unique<T>(v: T, i: number, a: T[]) { |
| return a.indexOf(v) === i; |
| } |
| |
| const nodeTypeIndex = new Map<NodeType, number>([ |
| ["github", 1], |
| // ["gitlab", 2], |
| ["volume", 3], |
| ["postgresql", 4], |
| ["mongodb", 5], |
| ["app", 6], |
| ["gateway-tcp", 7], |
| ["gateway-https", 8], |
| ]); |
| |
| function cmpNodes(x: AppNode, y: AppNode): number { |
| if (x.type === y.type) { |
| if (nodeLabel(x) < nodeLabel(y)) { |
| return -1; |
| } else if (nodeLabel(x) > nodeLabel(y)) { |
| return 1; |
| } |
| return 0; |
| } |
| // TODO(gio): why ! |
| return (nodeTypeIndex.get(x.type!) || 0) - (nodeTypeIndex.get(y.type!) || 0); |
| } |
| |
| export function Details() { |
| const nodes = useNodes<AppNode>(); |
| const sorted = useMemo(() => nodes.filter((n) => n.type !== "network").sort(cmpNodes), [nodes]); |
| const [open, setOpen] = useState<string[]>([]); |
| const selected = useMemo(() => nodes.filter((n) => n.selected).map((n) => n.id), [nodes]); |
| const all = useMemo(() => open.concat(selected).filter(unique), [open, selected]); |
| const mode = useMode(); |
| const isDeployMode = mode === "deploy"; |
| |
| return ( |
| <Accordion |
| type="multiple" |
| value={all} |
| onValueChange={(v) => setOpen(v)} |
| className="flex flex-col overflow-y-auto" |
| > |
| {sorted.map((n, index) => ( |
| <> |
| {index > 0 && <Separator />} |
| <AccordionItem key={n.id} value={n.id} className="px-1"> |
| <AccordionTrigger className="!h-fit"> |
| <div className="flex flex-row space-x-2 items-center"> |
| <Icon type={n.type} /> |
| <span>{nodeLabel(n)}</span> |
| </div> |
| </AccordionTrigger> |
| <AccordionContent className="pt-1"> |
| <NodeDetails node={n} disabled={isDeployMode} /> |
| </AccordionContent> |
| </AccordionItem> |
| </> |
| ))} |
| </Accordion> |
| ); |
| } |