81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import { FilterList } from "@/components/filter-list";
|
|
import { formatLocalDateTime } from "@/lib/datetime";
|
|
import { formatBytes, listAudits } from "@/lib/store";
|
|
|
|
export default async function AuditsPage() {
|
|
const audits = await listAudits();
|
|
|
|
return (
|
|
<main className="page-stack management-page">
|
|
<section className="hero-panel hero-panel--compact">
|
|
<div className="hero-copy">
|
|
<span className="eyebrow">审计</span>
|
|
<h2>鉴权审计</h2>
|
|
<span className="status-pill">最近 {audits.length} 条</span>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="panel-card dense-panel">
|
|
<FilterList
|
|
className="entity-table entity-table--audits"
|
|
placeholder="搜索节点、用户、来源、原因…"
|
|
statuses={[
|
|
{ value: "ok", label: "允许" },
|
|
{ value: "denied", label: "拒绝" },
|
|
]}
|
|
header={
|
|
<div className="entity-table__head audit-row-grid">
|
|
<span>结果</span>
|
|
<span>节点 / 用户</span>
|
|
<span>来源</span>
|
|
<span>请求速率</span>
|
|
<span>原因</span>
|
|
<span>时间</span>
|
|
</div>
|
|
}
|
|
items={audits.map((audit) => ({
|
|
id: audit.id,
|
|
text: `${audit.node_name ?? ""} ${audit.username ?? ""} ${audit.auth_id ?? ""} ${audit.addr ?? ""} ${audit.reason}`,
|
|
status: audit.ok ? "ok" : "denied",
|
|
content: (
|
|
<div
|
|
key={audit.id}
|
|
className="entity-table__summary audit-row-grid"
|
|
>
|
|
<span>
|
|
<span
|
|
className={`status-pill ${audit.ok ? "status-pill--ok" : "status-pill--danger"}`}
|
|
>
|
|
{audit.ok ? "允许" : "拒绝"}
|
|
</span>
|
|
</span>
|
|
<span className="entity-main-cell">
|
|
<strong>{audit.node_name ?? "未知节点"}</strong>
|
|
<span className="muted mono break-all">
|
|
{audit.username ?? audit.auth_id ?? "-"}
|
|
</span>
|
|
</span>
|
|
<span className="entity-code-cell break-all">
|
|
{audit.addr ?? "-"}
|
|
</span>
|
|
<span className="entity-number-cell">
|
|
<strong>
|
|
{audit.requested_tx != null
|
|
? formatBytes(audit.requested_tx)
|
|
: "-"}
|
|
</strong>
|
|
<span>/s</span>
|
|
</span>
|
|
<span>{audit.reason}</span>
|
|
<span className="entity-muted-cell">
|
|
{formatLocalDateTime(audit.created_at)}
|
|
</span>
|
|
</div>
|
|
),
|
|
}))}
|
|
/>
|
|
</section>
|
|
</main>
|
|
);
|
|
}
|