import { StatusCard } from "@/components/admin/dashboard"; import { prisma } from "@/lib/prisma"; export const dynamic = "force-dynamic"; // navigator_flatcats โ€” emulator-owned flat (private-room) categories shown in the // navigator. The Prisma delegate exists because the table has a primary key. type Flatcat = { id: number; caption: string; captionSave: string; minRank: number; maxUserCount: number; canTrade: string; public: string; listType: number; orderNum: number; }; // navigator_publics โ€” emulator-owned public-room assignments. This table has no // primary/unique key, so Prisma marks the model `@@ignore` and generates NO // delegate (prisma.navigatorPublics does not exist). It must be read via raw SQL. type PublicRow = { public_cat_id: number; room_id: number; visible: string; }; // Reusable yes/no pill so emulator boolean-ish "1"/"0" columns read consistently. function YesNo({ on }: { on: boolean }) { return ( {on ? "Yes" : "No"} ); } export default async function AdminNavigation() { let flatcats: Flatcat[] = []; try { flatcats = await prisma.navigatorFlatcats.findMany({ select: { id: true, caption: true, captionSave: true, minRank: true, maxUserCount: true, canTrade: true, public: true, listType: true, orderNum: true, }, orderBy: [{ orderNum: "asc" }, { id: "asc" }], }); } catch { flatcats = []; } // Raw read because navigator_publics is an `@@ignore`d (keyless) model. let publics: PublicRow[] = []; try { publics = await prisma.$queryRaw` SELECT public_cat_id, room_id, visible FROM navigator_publics ORDER BY public_cat_id ASC, room_id ASC `; } catch { publics = []; } // Resolve the public-category names and room names referenced by the rows above // so the read-only view is legible. Each lookup degrades to an empty map on error. const catIds = Array.from(new Set(publics.map((p) => p.public_cat_id))); const roomIds = Array.from(new Set(publics.map((p) => p.room_id))); let catNameById = new Map(); if (catIds.length) { try { const cats = await prisma.navigatorPubliccats.findMany({ where: { id: { in: catIds } }, select: { id: true, name: true }, }); catNameById = new Map(cats.map((c) => [c.id, c.name])); } catch { catNameById = new Map(); } } let roomNameById = new Map(); if (roomIds.length) { try { const rooms = await prisma.rooms.findMany({ where: { id: { in: roomIds } }, select: { id: true, name: true }, }); roomNameById = new Map(rooms.map((r) => [r.id, r.name])); } catch { roomNameById = new Map(); } } const publicFlatcats = flatcats.filter((c) => c.public === "1").length; const visiblePublics = publics.filter((p) => p.visible === "1").length; return (

Navigator

Read-only ยท the navigator config is owned by the emulator. Edit it in your emulator tooling, not here.

0 ? "ok" : "neutral"} icon="๐Ÿ‘๏ธ" />
{/* โ”€โ”€ navigator_flatcats โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}

Flat categories

navigator_flatcats ยท {flatcats.length} rows

{flatcats.length === 0 ? (

No flat categories found.

) : (
{flatcats.map((c) => ( ))}
ID Caption Caption (save) Min rank Max users Can trade Public List type Order
{c.id} {c.caption || "โ€”"} {c.captionSave || "โ€”"} {c.minRank} {c.maxUserCount} {c.listType} {c.orderNum}
)}
{/* โ”€โ”€ navigator_publics โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */}

Public rooms

navigator_publics ยท {publics.length} rows

{publics.length === 0 ? (

No public-room assignments found.

) : (
{publics.map((p, i) => ( ))}
Public cat Room Visible
{catNameById.get(p.public_cat_id) ?? "โ€”"}{" "} #{p.public_cat_id} {roomNameById.get(p.room_id) || "(unnamed)"}{" "} #{p.room_id}
)}
); }