feat(hk): expand search and add operational user overview
CI / check (push) Successful in 54s
CI / deploy (push) Successful in 1m16s
CI / publish-container (push) Successful in 1m57s

This commit is contained in:
Simo committed 2026-09-09 21:14:10 +02:00
1 parent 27447ce029
commit 89526af344
44 files changed
+3740 -416

No files matched your search

+3
View File
@@ -54,6 +54,9 @@ vi.mock("@/lib/db", () => {
where() {
return query;
},
orderBy() {
return query;
},
async limit() {
state.queried.push(table);
return [{ id: 1, title: "Match", subtitle: "Data" }];
+22
View File
@@ -0,0 +1,22 @@
import { describe, expect, it } from "vitest";
import { AdminSearchRequest } from "./admin-search-request";
describe("admin search request ownership", () => {
it("rejects a late response after the input changes, even before the next debounce fires", async () => {
const requests = new AdminSearchRequest();
const first = requests.start();
const late = Promise.resolve().then(() => requests.accepts(first));
requests.cancel();
expect(await late).toBe(false);
expect(first.signal.aborted).toBe(true);
});
it("accepts only the newest request and rejects completion after closing", () => {
const requests = new AdminSearchRequest();
const first = requests.start();
const second = requests.start();
expect(requests.accepts(first)).toBe(false);
expect(requests.accepts(second)).toBe(true);
requests.cancel();
expect(requests.accepts(second)).toBe(false);
});
});
+20
View File
@@ -0,0 +1,20 @@
/** Owns the single request allowed to update a search dialog. */
export class AdminSearchRequest {
private current: AbortController | null = null;
cancel() {
this.current?.abort();
this.current = null;
}
start() {
this.cancel();
const controller = new AbortController();
this.current = controller;
return controller;
}
accepts(controller: AbortController) {
return this.current === controller && !controller.signal.aborted;
}
}
+6 -4
View File
@@ -36,16 +36,18 @@ describe("staff smoke contract", () => {
expect(detail).toContain("canLiftBan");
});
it("exposes sanction timeline on user show", () => {
it("exposes operational overview on user show", () => {
expect(
existsSync("src/app/admin/users/_components/user-sanction-timeline.tsx"),
existsSync(
"src/app/admin/users/_components/user-operational-overview.tsx",
),
).toBe(true);
expect(existsSync("src/app/admin/users/_lib/load-user-sanctions.ts")).toBe(
expect(existsSync("src/app/admin/users/_lib/load-user-overview.ts")).toBe(
true,
);
expect(
readFileSync("src/app/admin/users/show/[id]/page.tsx", "utf8"),
).toContain("UserSanctionTimeline");
).toContain("UserOperationalOverview");
});
it("applies CMS SQL from drizzle/migrations (not Prisma)", () => {