logs route behind protected route and menu

This commit is contained in:
2026-03-16 20:59:05 -05:00
parent 5db2a7fe75
commit 2846b9cb0d
27 changed files with 1898 additions and 226 deletions

View File

@@ -1,69 +1,40 @@
import { createFileRoute, useRouter } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import socket from "@/lib/socket.io";
import {
createFileRoute,
useNavigate,
useRouter,
} from "@tanstack/react-router";
import { toast } from "sonner";
import z from "zod";
import { Button } from "../components/ui/button";
import { authClient, useSession } from "../lib/auth-client";
export const Route = createFileRoute("/")({
validateSearch: z.object({
redirect: z.string().optional(),
}),
component: Index,
});
interface LogEntry {
level: number;
createdAt: Date;
pid: number;
hostname: string;
module: string;
message?: string;
[key: string]: any; // catch any extra fields
}
function Index() {
const { data: session, isPending } = useSession();
const [logs, setLogs] = useState<LogEntry[]>([]);
const router = useRouter();
useEffect(() => {
// Connect if not already connected
if (!socket.connected) {
socket.connect();
}
socket.on("connect", () => {
socket.emit("join-room", "logs");
});
socket.emit("join-room", "logs");
socket.on(
"room-update",
(data: { payloads: LogEntry[]; roomId: string }) => {
setLogs((prev) => [...data.payloads, ...prev]);
},
);
// socket.on("logs", (data) => {
// console.log(data);
// setLogs((prev) => [...data.payloads, ...prev]);
// });
// Cleanup listeners on unmount
return () => {
socket.emit("leave-room", "logs");
socket.off("room-update");
socket.off("logs");
};
}, []); // empty array = runs once on mount
const removeLog = (i: LogEntry) => {
setLogs(logs.filter((l) => l.id !== i.id));
};
const navigate = useNavigate();
const search = Route.useSearch();
const login = async () => {
try {
await authClient.signIn.email({
email: "blake.matthes@alpla.com",
password: "nova0511",
fetchOptions: {
onSuccess: () => {
navigate({ to: search.redirect ?? "/" });
},
},
});
toast.success("logged in");
} catch (error: any) {
console.error(error.response);
}
@@ -74,7 +45,6 @@ function Index() {
if (isPending) return <div>Loading...</div>;
// if (!session) return <button>Sign In</button>
return (
<div className="p-2">
<h3 className="w-2xl text-3xl">Welcome Home!</h3>
@@ -86,80 +56,6 @@ function Index() {
<Button onClick={() => authClient.signOut()}>Signout</Button>
</div>
)}
{/* Log Table */}
<div className="rounded border overflow-auto max-h-[600px]">
<table className="w-full text-sm">
<thead className="bg-muted sticky top-0">
<tr>
<th className="text-left px-3 py-2">Time</th>
<th className="text-left px-3 py-2">Level</th>
<th className="text-left px-3 py-2">Module</th>
<th className="text-left px-3 py-2">Host</th>
<th className="text-left px-3 py-2">PID</th>
<th className="text-left px-3 py-2">Message</th>
<th className="text-left px-3 py-2">logId</th>
<th className="text-left px-3 py-2">remove</th>
</tr>
</thead>
<tbody>
{logs.length === 0 ? (
<tr>
<td
colSpan={6}
className="text-center py-6 text-muted-foreground"
>
No logs yet join the room to start receiving
</td>
</tr>
) : (
logs.map((log, i) => (
<tr
key={`${log.id}-${i}`}
className="border-t hover:bg-muted/50"
>
<td className="px-3 py-2 whitespace-nowrap">
{new Date(log.createdAt).toLocaleTimeString()}
</td>
<td className="px-3 py-2">
<LevelBadge level={log.level} />
</td>
<td className="px-3 py-2">{log.module}</td>
<td className="px-3 py-2">{log.hostname}</td>
<td className="px-3 py-2">{log.pid}</td>
<td className="px-3 py-2 max-w-sm truncate">{log.message}</td>
<td className="px-3 py-2">{log.id}</td>
<td className="px-3 py-2">
<Button onClick={() => removeLog(log)}>Delete</Button>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
);
}
function LevelBadge({ level }: { level: number }) {
const config: Record<number, { label: string; className: string }> = {
10: { label: "TRACE", className: "bg-gray-100 text-gray-600" },
20: { label: "DEBUG", className: "bg-blue-100 text-blue-700" },
30: { label: "INFO", className: "bg-green-100 text-green-700" },
40: { label: "WARN", className: "bg-yellow-100 text-yellow-700" },
50: { label: "ERROR", className: "bg-red-100 text-red-700" },
60: { label: "FATAL", className: "bg-purple-100 text-purple-700" },
};
const { label, className } = config[level] ?? {
label: String(level),
className: "bg-gray-100",
};
return (
<span className={`px-2 py-0.5 rounded text-xs font-medium ${className}`}>
{label}
</span>
);
}