Service caching and a few ui stuff

This commit is contained in:
2025-07-19 10:18:03 -05:00
parent 2151228b85
commit 96f174dd0e
7 changed files with 58 additions and 140 deletions
+8 -3
View File
@@ -1,7 +1,10 @@
import axios, { HttpStatusCode } from "axios"; import axios, { HttpStatusCode } from "axios";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { servers } from "../servers/servers"; import { PORT, servers } from "../servers/servers";
import validate from "../auth/auth"; import validate from "../auth/auth";
import Service from "@/types/service";
const allServices: { [key: string]: Service[] } = {};
export async function GET(request: Request) { export async function GET(request: Request) {
const { searchParams } = new URL(request.url); const { searchParams } = new URL(request.url);
@@ -26,10 +29,12 @@ export async function GET(request: Request) {
const server = servers.data[parseInt(index)]; const server = servers.data[parseInt(index)];
const apps = await axios.get(`http://${server.ip}:8080/apps`, {params: {auth: 'my-key'}}); axios.get(`http://${server.ip}:${PORT}/apps`, {params: {auth: 'my-key'}}).then((apps) => {
allServices[parseInt(index)] = apps.data;
});
return NextResponse.json({ return NextResponse.json({
message: "ok", message: "ok",
apps: apps.data, apps: allServices[parseInt(index)] || [],
}); });
} }
+5 -1
View File
@@ -2,6 +2,8 @@ import Server, { ServerAPI } from "@/types/server";
import Data from "../data"; import Data from "../data";
import axios from "axios"; import axios from "axios";
export const PORT = 63774;
export const useServer = (server: ServerAPI, index: number) => { export const useServer = (server: ServerAPI, index: number) => {
const interval = setInterval(() => { const interval = setInterval(() => {
if (deletes.has(index) || !currentServers[index]) { if (deletes.has(index) || !currentServers[index]) {
@@ -9,7 +11,7 @@ export const useServer = (server: ServerAPI, index: number) => {
interval.close(); interval.close();
return; return;
} }
axios.get(`http://${server.ip}:8080/`, {params: {auth: 'my-key'}}).then(({data}) => { axios.get(`http://${server.ip}:${PORT}/`, {params: {auth: 'my-key'}}).then(({data}) => {
if (data.status) { if (data.status) {
currentServers[index].status = data.status; currentServers[index].status = data.status;
} }
@@ -25,7 +27,9 @@ export const useServer = (server: ServerAPI, index: number) => {
if (data.network) { if (data.network) {
currentServers[index].network = data.network; currentServers[index].network = data.network;
} }
currentServers[index].status = 'online';
}).catch((e) => { }).catch((e) => {
currentServers[index].status = 'offline';
console.error(e.data); console.error(e.data);
}) })
}, 2000); }, 2000);
+4 -3
View File
@@ -24,6 +24,7 @@ import {
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress"; import { Progress } from "@/components/ui/progress";
import Session from "@/lib/session"; import Session from "@/lib/session";
import { cn } from "@/lib/utils";
import Server from "@/types/server"; import Server from "@/types/server";
import { import {
Cpu, Cpu,
@@ -130,12 +131,12 @@ export default function ServerComponent({
<div> <div>
<CardTitle>{server.name}</CardTitle> <CardTitle>{server.name}</CardTitle>
<CardDescription className="flex justify-between"> <CardDescription className="flex justify-between">
<div className="flex gap-2 items-center flex-wrap"> <div className="flex items-center flex-wrap">
{server.status[0].toUpperCase() + server.status.slice(1)} <div className={cn("mr-1", server.status)}>{server.status[0].toUpperCase() + server.status.slice(1)}</div>
{" · "} {" · "}
{server.ip} {server.ip}
{server.location && ( {server.location && (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1 ml-2">
<MapPin size={14} /> <MapPin size={14} />
{server.location} {server.location}
</div> </div>
+8
View File
@@ -303,3 +303,11 @@ body {
.sidebar div { .sidebar div {
border-radius: 14px !important; border-radius: 14px !important;
} }
.online {
color: var(--chart-3) !important;
}
.offline {
color: var(--chart-4) !important;
}
+6 -1
View File
@@ -15,13 +15,18 @@ export default function ServerPage() {
useEffect(() => { useEffect(() => {
session?.getServerIndex(0).then((s) => { session?.getServerIndex(0).then((s) => {
setServer(s.data); setServer(s.data);
setTimeout(() => {
session?.getServerIndex(0).then((s) => {
setServer(s.data);
});
}, 1000);
}); });
}, [session]); }, [session]);
return server && ( return server && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
{server.apps.map((a, i) => ( {server.apps.map((a, i) => (
<ServiceComponent key={i} server={a} index={i} session={session} / > <ServiceComponent key={i} service={a} index={i} session={session} / >
))} ))}
</div> </div>
); );
+26 -132
View File
@@ -1,13 +1,3 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { import {
Card, Card,
CardContent, CardContent,
@@ -15,32 +5,13 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress"; import { Progress } from "@/components/ui/progress";
import Session from "@/lib/session"; import Session from "@/lib/session";
import Server from "@/types/server"; import Service from "@/types/service";
import { import { AppWindowMac } from "lucide-react";
AppWindow,
AppWindowMac,
Cpu,
HardDrive,
MapPin,
MemoryStick,
Network,
Pencil,
ServerIcon,
Trash,
Wifi,
} from "lucide-react";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { toast } from "sonner";
export function UsageBar({ export function UsageBar({
value, value,
@@ -104,116 +75,39 @@ export function ByteUnit({
} }
export default function ServiceComponent({ export default function ServiceComponent({
server: service, service,
index, index,
session, session,
}: { }: {
server: { name?: string, description?: string }; service: Service;
index: number; index: number;
session: Session | null; session: Session | null;
}) { }) {
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
return ( return (
<> <Card
<ContextMenu> className="w-full transition-transform duration-500 hover:scale-102 hover:cursor-pointer !select-none"
<ContextMenuTrigger> onClick={() => {
<Card redirect(`/servers/${index}`);
className="w-full transition-transform duration-500 hover:scale-102 hover:cursor-pointer !select-none" }}
onClick={() => { >
redirect(`/servers/${index}`); <CardHeader>
}} <div className="flex items-center gap-2 overflow-clip">
> <div className="bg-muted text-muted-foreground p-1.5 rounded-md">
<CardHeader> <AppWindowMac className="w-4.5 h-4.5 text-current my-auto" />
<div className="flex items-center gap-2 overflow-clip"> </div>
<div className="bg-muted text-muted-foreground p-1.5 rounded-md"> <div>
<AppWindowMac className="w-4.5 h-4.5 text-current my-auto" /> <CardTitle>{service.name}</CardTitle>
</div>
<div>
<CardTitle>{service.name}</CardTitle>
{(service.description && <CardDescription className="flex justify-between"> {(service.description && <CardDescription className="flex justify-between">
{service.description} {(service as any).cpu} {service.description} {(service as any).cpu}
</CardDescription>)} </CardDescription>)}
</div> </div>
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="w-full flex flex-col gap-3.5"> <CardContent className="w-full flex flex-col gap-3.5">
{/* <UsageBar </CardContent>
value={service.cpu} </Card>
Icon={Cpu}
text="CPU"
color="var(--chart-2)"
/>
<UsageBar
value={service.memory}
Icon={MemoryStick}
text="Memory"
color="var(--chart-1)"
/>
<UsageBar
value={service.storage}
Icon={HardDrive}
text="Storage"
color="var(--chart-5)"
/> */}
{/* <div className="flex flex-col gap-2 w-full">
<div className="justify-between flex">
<Label className="text-md flex justify-center">
<Network size={16} color="var(--chart-3)" /> Network
</Label>
<Label className="text-md">{formatBytes(service.network)}</Label>
</div>
</div> */}
</CardContent>
</Card>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>
<Pencil className="text-current" />
Edit
</ContextMenuItem>
<ContextMenuItem
className="text-destructive"
onClick={() => setDeleteAlert(true)}
>
<Trash className="text-current" />
Delete
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
<AlertDialog open={deleteAlert} onOpenChange={setDeleteAlert}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription>
This action will permanently remove your server from the server
list
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
className="text-destructive-foreground bg-destructive"
onClick={() =>
session
?.removeServer(index)
.then(() => {
toast.info("Server successfully deleted");
})
.catch((e) => {
toast.error(
`Error deleting server: ` + e.response.data.message
);
})
}
>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
); );
} }
+1
View File
@@ -0,0 +1 @@
export default interface Service { name?: string, description?: string };