Add admin dashboard filtering and sorting
CI / verify (push) Has been cancelled
CI / publish (push) Has been cancelled

Provide stable server-side list queries and focused chart controls so operators can inspect large datasets without misleading partial-page ordering.
This commit is contained in:
Rocky
2026-08-20 18:05:49 +08:00
parent 034a3e8745
commit 74c3fcd45f
39 changed files with 2990 additions and 431 deletions
+46 -23
View File
@@ -1,10 +1,21 @@
import type { TrendPoint } from "../../api/types";
import { formatNumber } from "../../lib/format";
export function TrendChart({ points }: { points: TrendPoint[] }) {
export function TrendChart({
points,
showRegistrations = true,
showCredits = true,
}: {
points: TrendPoint[];
showRegistrations?: boolean;
showCredits?: boolean;
}) {
if (points.length === 0) {
return <div className="grid h-full place-items-center text-sm text-muted"></div>;
}
if (!showRegistrations && !showCredits) {
return <div className="grid h-full place-items-center text-sm text-muted"></div>;
}
const width = 760;
const height = 300;
@@ -53,26 +64,38 @@ export function TrendChart({ points }: { points: TrendPoint[] }) {
className="chart-grid-line"
/>
))}
<text x={paddingX} y={paddingY - 9} className="chart-label">
{formatNumber(registrationMax)}
</text>
<text x={width - paddingX} y={paddingY - 9} textAnchor="end" className="chart-label">
{formatNumber(creditMax)}
</text>
<polyline points={registrationLine} className="chart-line chart-line--primary" />
<polyline points={creditLine} className="chart-line chart-line--violet" />
{showRegistrations ? (
<text x={paddingX} y={paddingY - 9} className="chart-label">
{formatNumber(registrationMax)}
</text>
) : null}
{showCredits ? (
<text x={width - paddingX} y={paddingY - 9} textAnchor="end" className="chart-label">
{formatNumber(creditMax)}
</text>
) : null}
{showRegistrations ? (
<polyline points={registrationLine} className="chart-line chart-line--primary" />
) : null}
{showCredits ? (
<polyline points={creditLine} className="chart-line chart-line--violet" />
) : null}
{coordinates.map(({ point, x, registrationY, creditY }, index) => (
<g key={point.date}>
<circle cx={x} cy={registrationY} r="4" className="chart-dot chart-dot--primary">
<title>
{point.date} {formatNumber(point.registrations)}
</title>
</circle>
<circle cx={x} cy={creditY} r="3.5" className="chart-dot chart-dot--violet">
<title>
{point.date} {formatNumber(point.creditsUsed)}
</title>
</circle>
{showRegistrations ? (
<circle cx={x} cy={registrationY} r="4" className="chart-dot chart-dot--primary">
<title>
{point.date} {formatNumber(point.registrations)}
</title>
</circle>
) : null}
{showCredits ? (
<circle cx={x} cy={creditY} r="3.5" className="chart-dot chart-dot--violet">
<title>
{point.date} {formatNumber(point.creditsUsed)}
</title>
</circle>
) : null}
{index % labelEvery === 0 || index === points.length - 1 ? (
<text
x={x}
@@ -92,16 +115,16 @@ export function TrendChart({ points }: { points: TrendPoint[] }) {
<thead>
<tr>
<th scope="col">UTC </th>
<th scope="col"></th>
<th scope="col"></th>
{showRegistrations ? <th scope="col"></th> : null}
{showCredits ? <th scope="col"></th> : null}
</tr>
</thead>
<tbody>
{points.map((point) => (
<tr key={point.date}>
<td>{point.date}</td>
<td>{formatNumber(point.registrations)}</td>
<td>{formatNumber(point.creditsUsed)}</td>
{showRegistrations ? <td>{formatNumber(point.registrations)}</td> : null}
{showCredits ? <td>{formatNumber(point.creditsUsed)}</td> : null}
</tr>
))}
</tbody>