Adapt + improve all admin pages to the new design system
Swept the whole housekeeping panel (34 pages) so it's a consistent, improved adaptation of the old Filament admin rather than bare tables: - Live status tiles (StatusCard) summarising each page's data — counts and stateful metrics (users online, active/permanent bans, pending applications, settings, radio shouts, etc.). - Status pills (admin-badge ok/danger) replacing ad-hoc text: online/ offline, account/ip ban types, permanent vs timed, command OK/FAIL, alert severity & read/new, enabled/disabled, open/closed. - Sections wrapped in .admin-section with h2 headers; redundant inline table styling removed (the global .admin layer handles it). - alerts/logs/emulator hand-built as the reference pattern; the rest via parallel agents that read the schema and preserved every server action, query and field name. Behaviour unchanged (same actions, queries, field names). Verified in a real authed admin session (prod, amx_test): pages render with live data (Users tiles show 7 real accounts + online/offline pills), no errors. tsc 0, vitest 49/49, next build 0.
This commit is contained in:
1 parent
d419731566
commit
0de0ac6a3c
34 files changed
+2357
-1396
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
@@ -25,6 +26,13 @@ type PublicRow = {
|
||||
visible: string;
|
||||
};
|
||||
|
||||
// Reusable yes/no pill so emulator boolean-ish "1"/"0" columns read consistently.
|
||||
function YesNo({ on }: { on: boolean }) {
|
||||
return (
|
||||
<span className={`admin-badge ${on ? "ok" : "danger"}`}>{on ? "Yes" : "No"}</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default async function AdminNavigation() {
|
||||
let flatcats: Flatcat[] = [];
|
||||
try {
|
||||
@@ -89,97 +97,121 @@ export default async function AdminNavigation() {
|
||||
}
|
||||
}
|
||||
|
||||
const publicFlatcats = flatcats.filter((c) => c.public === "1").length;
|
||||
const visiblePublics = publics.filter((p) => p.visible === "1").length;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Navigator</h1>
|
||||
<p className="muted" style={{ marginTop: 0 }}>
|
||||
<p className="muted" style={{ marginTop: "-0.4rem" }}>
|
||||
Read-only · the navigator config is owned by the emulator. Edit it in your
|
||||
emulator tooling, not here.
|
||||
</p>
|
||||
|
||||
{/* ── navigator_flatcats ───────────────────────────────── */}
|
||||
<div className="card" style={{ padding: 0, overflowX: "auto", marginBottom: "1.5rem" }}>
|
||||
<div style={{ padding: "1.1rem 1.25rem 0" }}>
|
||||
<h3 style={{ margin: 0 }}>Flat categories</h3>
|
||||
<p className="muted" style={{ margin: "0.25rem 0 0" }}>
|
||||
<code>navigator_flatcats</code> · {flatcats.length} rows
|
||||
</p>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Caption</th>
|
||||
<th>Caption (save)</th>
|
||||
<th>Min rank</th>
|
||||
<th>Max users</th>
|
||||
<th>Can trade</th>
|
||||
<th>Public</th>
|
||||
<th>List type</th>
|
||||
<th>Order</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{flatcats.map((c) => (
|
||||
<tr key={c.id}>
|
||||
<td>{c.id}</td>
|
||||
<td>{c.caption || "—"}</td>
|
||||
<td>{c.captionSave || "—"}</td>
|
||||
<td>{c.minRank}</td>
|
||||
<td>{c.maxUserCount}</td>
|
||||
<td>{c.canTrade === "1" ? "Yes" : "No"}</td>
|
||||
<td>{c.public === "1" ? "Yes" : "No"}</td>
|
||||
<td>{c.listType}</td>
|
||||
<td>{c.orderNum}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{flatcats.length === 0 ? (
|
||||
<p className="muted" style={{ padding: "0 1.25rem 1.1rem" }}>
|
||||
No flat categories found.
|
||||
</p>
|
||||
) : null}
|
||||
<div className="admin-stats">
|
||||
<StatusCard label="Flat categories" value={flatcats.length} icon="📂" />
|
||||
<StatusCard
|
||||
label="Public (flatcats)"
|
||||
value={publicFlatcats}
|
||||
hint="marked public"
|
||||
icon="🌐"
|
||||
/>
|
||||
<StatusCard label="Public rooms" value={publics.length} icon="🚪" />
|
||||
<StatusCard
|
||||
label="Visible rooms"
|
||||
value={visiblePublics}
|
||||
state={visiblePublics > 0 ? "ok" : "neutral"}
|
||||
icon="👁️"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* ── navigator_flatcats ───────────────────────────────── */}
|
||||
<section className="admin-section">
|
||||
<h2>Flat categories</h2>
|
||||
<p className="muted" style={{ marginTop: "-0.4rem" }}>
|
||||
<code>navigator_flatcats</code> · {flatcats.length} rows
|
||||
</p>
|
||||
{flatcats.length === 0 ? (
|
||||
<p className="muted">No flat categories found.</p>
|
||||
) : (
|
||||
<div style={{ overflowX: "auto" }}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Caption</th>
|
||||
<th>Caption (save)</th>
|
||||
<th>Min rank</th>
|
||||
<th>Max users</th>
|
||||
<th>Can trade</th>
|
||||
<th>Public</th>
|
||||
<th>List type</th>
|
||||
<th>Order</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{flatcats.map((c) => (
|
||||
<tr key={c.id}>
|
||||
<td className="muted">{c.id}</td>
|
||||
<td>{c.caption || "—"}</td>
|
||||
<td className="muted">{c.captionSave || "—"}</td>
|
||||
<td>{c.minRank}</td>
|
||||
<td>{c.maxUserCount}</td>
|
||||
<td>
|
||||
<YesNo on={c.canTrade === "1"} />
|
||||
</td>
|
||||
<td>
|
||||
<YesNo on={c.public === "1"} />
|
||||
</td>
|
||||
<td>{c.listType}</td>
|
||||
<td>{c.orderNum}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* ── navigator_publics ────────────────────────────────── */}
|
||||
<div className="card" style={{ padding: 0, overflowX: "auto" }}>
|
||||
<div style={{ padding: "1.1rem 1.25rem 0" }}>
|
||||
<h3 style={{ margin: 0 }}>Public rooms</h3>
|
||||
<p className="muted" style={{ margin: "0.25rem 0 0" }}>
|
||||
<code>navigator_publics</code> · {publics.length} rows
|
||||
</p>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Public cat</th>
|
||||
<th>Room</th>
|
||||
<th>Visible</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{publics.map((p, i) => (
|
||||
<tr key={`${p.public_cat_id}-${p.room_id}-${i}`}>
|
||||
<td>
|
||||
{catNameById.get(p.public_cat_id) ?? "—"}{" "}
|
||||
<span className="muted">#{p.public_cat_id}</span>
|
||||
</td>
|
||||
<td>
|
||||
{roomNameById.get(p.room_id) || "(unnamed)"}{" "}
|
||||
<span className="muted">#{p.room_id}</span>
|
||||
</td>
|
||||
<td>{p.visible === "1" ? "Yes" : "No"}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<section className="admin-section">
|
||||
<h2>Public rooms</h2>
|
||||
<p className="muted" style={{ marginTop: "-0.4rem" }}>
|
||||
<code>navigator_publics</code> · {publics.length} rows
|
||||
</p>
|
||||
{publics.length === 0 ? (
|
||||
<p className="muted" style={{ padding: "0 1.25rem 1.1rem" }}>
|
||||
No public-room assignments found.
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="muted">No public-room assignments found.</p>
|
||||
) : (
|
||||
<div style={{ overflowX: "auto" }}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Public cat</th>
|
||||
<th>Room</th>
|
||||
<th>Visible</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{publics.map((p, i) => (
|
||||
<tr key={`${p.public_cat_id}-${p.room_id}-${i}`}>
|
||||
<td>
|
||||
{catNameById.get(p.public_cat_id) ?? "—"}{" "}
|
||||
<span className="muted">#{p.public_cat_id}</span>
|
||||
</td>
|
||||
<td>
|
||||
{roomNameById.get(p.room_id) || "(unnamed)"}{" "}
|
||||
<span className="muted">#{p.room_id}</span>
|
||||
</td>
|
||||
<td>
|
||||
<YesNo on={p.visible === "1"} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user