toast
This commit is contained in:
@@ -4,11 +4,11 @@ import Data, { findKey } from "../data";
|
||||
|
||||
const users = new Data<{
|
||||
[key: string]: { username: string; password: string };
|
||||
}>("sentryx/users.json", "object");
|
||||
}>("sentryx/users.json", { admin: { username: "admin", password: "admin" } });
|
||||
|
||||
const sessions = new Data<{ [key: string]: string }>(
|
||||
"sentryx/sessions.json",
|
||||
"object"
|
||||
{}
|
||||
);
|
||||
|
||||
export async function POST(request: Request) {
|
||||
@@ -44,9 +44,9 @@ export async function POST(request: Request) {
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
|
||||
const id = searchParams.get("id") || "";
|
||||
const sessionId = searchParams.get("sessionId") || "";
|
||||
|
||||
if (!sessions.data[id])
|
||||
if (!sessions.data[sessionId])
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid session" },
|
||||
{ status: HttpStatusCode.Unauthorized }
|
||||
@@ -54,3 +54,7 @@ export async function GET(request: Request) {
|
||||
|
||||
return NextResponse.json({ message: "ok" });
|
||||
}
|
||||
|
||||
export default function validate(sessionId: string) {
|
||||
return sessions.data[sessionId] != undefined;
|
||||
}
|
||||
|
||||
+10
-4
@@ -1,4 +1,5 @@
|
||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
||||
import { dirname } from "path";
|
||||
|
||||
export function findKey<T extends object>(
|
||||
obj: T,
|
||||
@@ -12,17 +13,17 @@ export function findKey<T extends object>(
|
||||
export default class Data<T> {
|
||||
data: T;
|
||||
file_path: string;
|
||||
constructor(file_path: string, type: "object" | "array") {
|
||||
constructor(file_path: string, def: T) {
|
||||
this.file_path = file_path;
|
||||
if (existsSync(file_path)) {
|
||||
try {
|
||||
this.data = JSON.parse(readFileSync(file_path, "utf-8"));
|
||||
} catch {
|
||||
this.data = (type == "object" ? {} : []) as T;
|
||||
this.data = def;
|
||||
this.write();
|
||||
}
|
||||
} else {
|
||||
this.data = (type == "object" ? {} : []) as T;
|
||||
this.data = def;
|
||||
this.write();
|
||||
}
|
||||
}
|
||||
@@ -32,6 +33,11 @@ export default class Data<T> {
|
||||
}
|
||||
|
||||
public write() {
|
||||
const dir = dirname(this.file_path);
|
||||
if (!existsSync(dir)) {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
writeFileSync(this.file_path, JSON.stringify(this.data));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ import { NextResponse } from "next/server";
|
||||
import Data from "../data";
|
||||
import Server, { ServerAPI } from "@/types/server";
|
||||
import { HttpStatusCode } from "axios";
|
||||
import validate from "../auth/route";
|
||||
|
||||
const servers = new Data<ServerAPI[]>("sentryx/servers.json", "array");
|
||||
const servers = new Data<ServerAPI[]>("sentryx/servers.json", []);
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
@@ -44,10 +45,16 @@ export async function GET(request: Request) {
|
||||
export async function POST(request: Request) {
|
||||
const body = await request.json();
|
||||
|
||||
if (!validate(body.sessionId))
|
||||
return NextResponse.json(
|
||||
{ message: "Invalid session" },
|
||||
{ status: HttpStatusCode.Unauthorized }
|
||||
);
|
||||
|
||||
if (!body.name || !body.ip)
|
||||
return NextResponse.json(
|
||||
{
|
||||
message: "Invalid body",
|
||||
message: "The name or IP are invalid or empty",
|
||||
},
|
||||
{
|
||||
status: HttpStatusCode.BadRequest,
|
||||
|
||||
@@ -8,7 +8,14 @@ import {
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import Server from "@/types/server";
|
||||
import { Cpu, HardDrive, MemoryStick, Network, Wifi } from "lucide-react";
|
||||
import {
|
||||
Cpu,
|
||||
HardDrive,
|
||||
MapPin,
|
||||
MemoryStick,
|
||||
Network,
|
||||
Wifi,
|
||||
} from "lucide-react";
|
||||
|
||||
function UsageBar({
|
||||
value,
|
||||
@@ -39,9 +46,17 @@ export default function ServerComponent({ server }: { server: Server }) {
|
||||
<Card className="w-full transition-transform duration-500 hover:scale-102 hover:cursor-pointer">
|
||||
<CardHeader>
|
||||
<CardTitle>{server.name}</CardTitle>
|
||||
<CardDescription>
|
||||
{server.status[0].toUpperCase() + server.status.slice(1)} {" · "}
|
||||
{server.ip}
|
||||
<CardDescription className="flex justify-between">
|
||||
<div className="flex gap-2">
|
||||
{server.status[0].toUpperCase() + server.status.slice(1)} {" · "}
|
||||
{server.ip}
|
||||
{server.location && (
|
||||
<div className="flex items-center gap-0.5">
|
||||
<MapPin size={14} />
|
||||
{server.location}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="w-full flex flex-col gap-3.5">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
import AppLayout from "@/components/AppLayout"; // import your wrapper
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sentryx Control Panel",
|
||||
@@ -16,6 +17,7 @@ export default function RootLayout({
|
||||
<html lang="en">
|
||||
<body className="antialiased dark">
|
||||
<AppLayout>{children}</AppLayout>
|
||||
<Toaster />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Label } from "@/components/ui/label";
|
||||
import MapSelect from "./LocationSelect";
|
||||
import { useState } from "react";
|
||||
import Session from "@/lib/session";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export default function NewServerDialog({
|
||||
session,
|
||||
@@ -24,7 +25,8 @@ export default function NewServerDialog({
|
||||
const [open, setOpen] = useState(false);
|
||||
const [name, setName] = useState("");
|
||||
const [ip, setIp] = useState("");
|
||||
const [location, setLocation] = useState<[number, number] | undefined>(
|
||||
const [location, setLocation] = useState<string | undefined>(undefined);
|
||||
const [coordinates, setCoordinates] = useState<[number, number] | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
@@ -52,12 +54,33 @@ export default function NewServerDialog({
|
||||
onInput={(e) => setIp(e.currentTarget.value)}
|
||||
/>
|
||||
|
||||
<Label className="mt-2">Server Location Name</Label>
|
||||
<Input
|
||||
placeholder="Home, Warehouse 1, 4th ave, etc"
|
||||
onInput={(e) =>
|
||||
setLocation(
|
||||
e.currentTarget.value == "" ? undefined : e.currentTarget.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<Label className="mt-2">Server Location</Label>
|
||||
<MapSelect setLocation={setLocation} />
|
||||
<MapSelect setLocation={setCoordinates} />
|
||||
<DialogFooter>
|
||||
<Button
|
||||
onClick={() => {
|
||||
session?.addServer({ name, ip, coordinates: location });
|
||||
session
|
||||
?.addServer({ name, ip, coordinates, location })
|
||||
.then(() => {
|
||||
toast.success(
|
||||
"Server added successfully, refresh to view it"
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
toast.error(
|
||||
"Error adding server: " + e.response.data.message
|
||||
);
|
||||
});
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -14,7 +14,7 @@ export default async function getSession(): Promise<Session | null> {
|
||||
|
||||
try {
|
||||
await axios.get("http://localhost:3000/api/auth", {
|
||||
params: { id: sessionId },
|
||||
params: { sessionId },
|
||||
});
|
||||
|
||||
return new Session(sessionId);
|
||||
|
||||
@@ -9,16 +9,13 @@ export default function useSession() {
|
||||
const [session, setSession] = useState<Session | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const id = Cookies.get("session_id");
|
||||
const sessionId = Cookies.get("session_id");
|
||||
|
||||
if (id)
|
||||
axios({
|
||||
method: "get",
|
||||
url: "/api/auth",
|
||||
params: { id },
|
||||
})
|
||||
if (sessionId)
|
||||
axios
|
||||
.get("/api/auth", { params: { sessionId } })
|
||||
.then((r) => {
|
||||
setSession(new Session(id));
|
||||
setSession(new Session(sessionId));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
|
||||
+2
-8
@@ -13,7 +13,7 @@ export default class Session {
|
||||
return (
|
||||
((
|
||||
await axios.get(`/api/servers?s=${query || ""}`, {
|
||||
params: { id: this.id },
|
||||
params: { sessionId: this.id },
|
||||
})
|
||||
).data.servers as Server[]) || []
|
||||
);
|
||||
@@ -23,12 +23,6 @@ export default class Session {
|
||||
}
|
||||
|
||||
public async addServer(s: ServerAPI) {
|
||||
try {
|
||||
return (
|
||||
((await axios.post("/api/servers", s)).data.servers as Server[]) || []
|
||||
);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
return await axios.post("/api/servers", { ...s, sessionId: this.id });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export interface ServerAPI {
|
||||
name: string;
|
||||
ip: string;
|
||||
location?: string;
|
||||
coordinates?: [number, number];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user