diff --git a/sentryx/servers.json b/sentryx/servers.json index 19839d2..e2ac3a6 100644 --- a/sentryx/servers.json +++ b/sentryx/servers.json @@ -1,12 +1 @@ -[ - { - "name": "Main Server", - "ip": "10.7.1.2", - "coordinates": [19.8187, 41.3275] - }, - { - "name": "Second Server", - "ip": "10.7.1.2", - "coordinates": [19.8187, 42] - } -] +[{"name":"Main Server","ip":"10.7.1.2","coordinates":[19.8187,41.3275]},{"name":"Second Server","ip":"10.7.1.2","coordinates":[19.8187,42]},{"name":"test","ip":"abc","coordinates":[14.212747852350674,13.997221304482736]},{"name":"Bro","ip":"10.7.1.53","coordinates":[19.66455594156352,40.826754398461304]},{"name":"Idk lol","ip":"10.32.2.4","coordinates":[20.135507417925936,41.17975477202245]}] \ No newline at end of file diff --git a/src/app/api/servers/route.ts b/src/app/api/servers/route.ts index f033783..2fd3340 100644 --- a/src/app/api/servers/route.ts +++ b/src/app/api/servers/route.ts @@ -1,6 +1,7 @@ import { NextResponse } from "next/server"; import Data from "../data"; import Server, { ServerAPI } from "@/types/server"; +import { HttpStatusCode } from "axios"; const servers = new Data("sentryx/servers.json", "array"); @@ -39,3 +40,29 @@ export async function GET(request: Request) { servers: currentServers, }); } + +export async function POST(request: Request) { + const body = await request.json(); + + if (!body.name || !body.ip) + return NextResponse.json( + { + message: "Invalid body", + }, + { + status: HttpStatusCode.BadRequest, + } + ); + + servers.data.push({ + name: body.name, + ip: body.ip, + coordinates: body.coordinates, + }); + + servers.write(); + + return NextResponse.json({ + message: "ok", + }); +} diff --git a/src/app/servers/LocationSelect.tsx b/src/app/servers/LocationSelect.tsx new file mode 100644 index 0000000..905899f --- /dev/null +++ b/src/app/servers/LocationSelect.tsx @@ -0,0 +1,60 @@ +import React, { useRef, useEffect, useState } from "react"; +import maplibregl from "maplibre-gl"; +import "maplibre-gl/dist/maplibre-gl.css"; + +export default function MapSelect({ + setLocation, +}: { + setLocation: (coors: [number, number]) => void; +}) { + const mapContainer = useRef(null); + const map = useRef(null); + const marker = useRef(null); + + useEffect(() => { + if (map.current || !mapContainer.current) return; + + map.current = new maplibregl.Map({ + container: mapContainer.current, + style: "/map_style.json", + center: [0, 0], + zoom: 2, + }); + + // Add click handler + map.current.on("click", (e) => { + const lngLat = e.lngLat; + + // Save location to state + setLocation([lngLat.lng, lngLat.lat]); + + // Remove previous marker if any + if (marker.current) { + marker.current.remove(); + } + + // Add marker to clicked location + marker.current = new maplibregl.Marker({ color: "#ff3e00" }) + .setLngLat(lngLat) + .addTo(map.current!); + }); + + return () => { + // Clean up marker + if (marker.current) { + marker.current.remove(); + marker.current = null; + } + + // Clean up map + map.current?.remove(); + map.current = null; + }; + }, []); + + return ( + <> +
+ + ); +} diff --git a/src/app/servers/Map.tsx b/src/app/servers/Map.tsx index 2a7515d..5c17c82 100644 --- a/src/app/servers/Map.tsx +++ b/src/app/servers/Map.tsx @@ -56,5 +56,5 @@ export default function Map({ servers }: { servers: Server[] }) { }); }, [servers]); - return
; + return
; } diff --git a/src/app/servers/NewServerDialog.tsx b/src/app/servers/NewServerDialog.tsx new file mode 100644 index 0000000..d59076d --- /dev/null +++ b/src/app/servers/NewServerDialog.tsx @@ -0,0 +1,70 @@ +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { Button, buttonVariants } from "@/components/ui/button"; +import { Plus } from "lucide-react"; +import { cn } from "@/lib/utils"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import MapSelect from "./LocationSelect"; +import { useState } from "react"; +import Session from "@/lib/session"; + +export default function NewServerDialog({ + session, +}: { + session: Session | null; +}) { + const [open, setOpen] = useState(false); + const [name, setName] = useState(""); + const [ip, setIp] = useState(""); + const [location, setLocation] = useState<[number, number] | undefined>( + undefined + ); + + return ( + + setOpen(true)} + > + New + + + + Add Server + + + setName(e.currentTarget.value)} + /> + + + setIp(e.currentTarget.value)} + /> + + + + + + + + + ); +} diff --git a/src/app/servers/page.tsx b/src/app/servers/page.tsx index 4763aaf..f3c9083 100644 --- a/src/app/servers/page.tsx +++ b/src/app/servers/page.tsx @@ -1,19 +1,14 @@ "use client"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { cn } from "@/lib/utils"; -import { CircleCheckBig, Cpu, MemoryStick, TriangleAlert } from "lucide-react"; -import { ChartAreaGradient } from "../dashboard/chart"; -import { Progress } from "@/components/ui/progress"; +import { Card, CardContent } from "@/components/ui/card"; import ServerComponent from "../dashboard/server"; import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; import { useEffect, useState } from "react"; import useSession from "@/hooks/useSession"; import Server from "@/types/server"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import Map from "./Map"; +import NewServerDialog from "./NewServerDialog"; export default function Servers() { const session = useSession(); @@ -45,20 +40,20 @@ export default function Servers() { }, [serversQuery, servers]); return ( -
- +
+ Grid Map - + setServersQuery(e.currentTarget.value)} placeholder="Search servers by name, location or IP..." /> - + diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..d9ccec9 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,143 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/src/lib/session.ts b/src/lib/session.ts index e9bb538..f966e32 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -1,4 +1,4 @@ -import Server from "@/types/server"; +import Server, { ServerAPI } from "@/types/server"; import axios from "axios"; export default class Session { @@ -21,4 +21,14 @@ export default class Session { return []; } } + + public async addServer(s: ServerAPI) { + try { + return ( + ((await axios.post("/api/servers", s)).data.servers as Server[]) || [] + ); + } catch { + return []; + } + } } diff --git a/src/types/server.ts b/src/types/server.ts index 88cd371..6098744 100644 --- a/src/types/server.ts +++ b/src/types/server.ts @@ -1,6 +1,7 @@ export interface ServerAPI { name: string; ip: string; + coordinates?: [number, number]; } export default interface Server extends ServerAPI { @@ -9,5 +10,4 @@ export default interface Server extends ServerAPI { memory: number; storage: number; network: number; - coordinates?: [number, number]; }