refactor(housekeeping): modal confirm, bulk delete, search debounce, audit inline, form reset

- Replace browser confirm() with custom ConfirmModal component
- Add search debounce (300ms) before syncing URL params
- Reset add-permission form after successful submit
- Add bulk select/delete with checkbox column and bulkDeletePermissions action
- AuditSection fetches logs server-side via getAuditLogs and shows inline table
- Add 10 new i18n keys (cancel, confirm, confirmDeletePermission,
  confirmBulkDelete, deleteSelected, confirmClearAllDesc,
  auditTime, auditUser, auditAction, auditTarget) synced to all 22 locales
This commit is contained in:
openhands committed 2026-07-17 19:53:53 +02:00
1 parent d693d169dd
commit f1e4e32a1e
25 files changed
+645 -137

No files matched your search

+8 -14
View File
@@ -3,7 +3,9 @@ import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
import { getAuditLogs } from "@/lib/services/audit";
import {
AuditSection,
ExportSection,
ImportSection,
ManageSection,
@@ -77,6 +79,11 @@ export default async function AdminHousekeeping({
const allGroups = [...new Set([...GROUPS, ...Object.keys(groupCounts)])];
const auditLogs = await getAuditLogs({
search: "housekeeping",
perPage: 25,
}).catch(() => null);
return (
<main>
<div className="admin-tabs mb-4">
@@ -308,20 +315,7 @@ export default async function AdminHousekeeping({
</section>
)}
{tab === "audit" && (
<section>
<h2 className="admin-section-title">{t("auditTitle")}</h2>
<p className="text-xs text-[var(--admin-text-muted)] -mt-2 mb-3">
{t("auditHint")}
</p>
<div className="admin-card">
<p className="text-sm opacity-70">{t("auditLogsAt")}</p>
<Link href="/admin/logs/audit" className="btn btn-outline mt-2">
{t("viewAuditLogs")}
</Link>
</div>
</section>
)}
{tab === "audit" && <AuditSection initialLogs={auditLogs} />}
</main>
);
}