From f1e4e32a1ed2f70bb8fd509ee8e26738ea649288 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 17 Jul 2026 19:53:53 +0200 Subject: [PATCH] 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 --- src/actions/admin-housekeeping.ts | 23 ++ src/app/admin/housekeeping/client.tsx | 473 ++++++++++++++++++++------ src/app/admin/housekeeping/page.tsx | 22 +- src/messages/bg.json | 12 +- src/messages/cs.json | 12 +- src/messages/da.json | 12 +- src/messages/de.json | 12 +- src/messages/el.json | 12 +- src/messages/en.json | 12 +- src/messages/es.json | 12 +- src/messages/fr.json | 12 +- src/messages/hr.json | 12 +- src/messages/hu.json | 12 +- src/messages/it.json | 12 +- src/messages/nl.json | 12 +- src/messages/no.json | 12 +- src/messages/pl.json | 12 +- src/messages/pt.json | 12 +- src/messages/ro.json | 12 +- src/messages/ru.json | 12 +- src/messages/sk.json | 12 +- src/messages/sr.json | 12 +- src/messages/sv.json | 12 +- src/messages/tr.json | 12 +- src/messages/uk.json | 12 +- 25 files changed, 645 insertions(+), 137 deletions(-) diff --git a/src/actions/admin-housekeeping.ts b/src/actions/admin-housekeeping.ts index 6928f6dd..029131f5 100644 --- a/src/actions/admin-housekeeping.ts +++ b/src/actions/admin-housekeeping.ts @@ -870,4 +870,27 @@ export async function clearAllPermissions(): Promise { revalidatePath("/admin/housekeeping"); } +export async function bulkDeletePermissions( + ids: bigint[], +): Promise<{ count: number }> { + await requirePermission(PERMS.SETTINGS_EDIT); + + if (!ids.length) return { count: 0 }; + + const userId = await currentUserId(); + + await prisma.websiteHousekeepingPermissions.deleteMany({ + where: { id: { in: ids } }, + }); + + await logAudit({ + userId: userId ?? 0, + action: "housekeeping.permission.bulk_delete", + target: "WebsiteHousekeepingPermissions", + after: { deletedCount: ids.length }, + }); + + revalidatePath("/admin/housekeeping"); + return { count: ids.length }; +} diff --git a/src/app/admin/housekeeping/client.tsx b/src/app/admin/housekeeping/client.tsx index a4a29c55..cca593a0 100644 --- a/src/app/admin/housekeeping/client.tsx +++ b/src/app/admin/housekeeping/client.tsx @@ -2,10 +2,11 @@ import { useRouter, useSearchParams } from "next/navigation"; import { useTranslations } from "next-intl"; -import { useCallback, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { toast } from "sonner"; import { applyPreset, + bulkDeletePermissions, bulkImportPermissions, clearAllPermissions, deletePermission, @@ -31,6 +32,61 @@ interface SharedProps { permSet: Set; } +/* ────────── Confirm Modal ────────── */ + +interface ConfirmModalProps { + open: boolean; + title: string; + message: string; + confirmLabel?: string; + cancelLabel?: string; + variant?: "danger" | "primary"; + onConfirm: () => void; + onCancel: () => void; +} + +function ConfirmModal({ + open, + title, + message, + confirmLabel, + cancelLabel, + variant = "danger", + onConfirm, + onCancel, +}: ConfirmModalProps) { + const t = useTranslations("pages.admin.housekeeping"); + if (!open) return null; + return ( +
+
e.stopPropagation()} + > +

{title}

+

{message}

+
+ + +
+
+
+ ); +} + +/* ────────── Manage Section ────────── */ + export function ManageSection(props: SharedProps) { const t = useTranslations("pages.admin.housekeeping"); const router = useRouter(); @@ -39,6 +95,11 @@ export function ManageSection(props: SharedProps) { const [groupFilter, setGroupFilter] = useState(sp.get("group") ?? ""); const [page, setPage] = useState(1); const [pendingDel, setPendingDel] = useState(null); + const [selected, setSelected] = useState>(new Set()); + const [busyBulk, setBusyBulk] = useState(false); + const [confirmDel, setConfirmDel] = useState(null); + const searchTimer = useRef>(null); + const formRef = useRef(null); const filtered = useMemo(() => { return props.permissions.filter((p) => { @@ -70,11 +131,26 @@ export function ManageSection(props: SharedProps) { [router], ); + const debouncedSync = useCallback( + (s: string, g: string) => { + if (searchTimer.current) clearTimeout(searchTimer.current); + searchTimer.current = setTimeout(() => syncUrl(s, g), 300); + }, + [syncUrl], + ); + + useEffect(() => { + return () => { + if (searchTimer.current) clearTimeout(searchTimer.current); + }; + }, []); + const handleUpsert = useCallback( async (formData: FormData) => { try { await upsertPermission(formData); toast.success(t("saved")); + if (formRef.current) formRef.current.reset(); router.refresh(); } catch { toast.error(t("errorOccurred")); @@ -85,7 +161,6 @@ export function ManageSection(props: SharedProps) { const handleDelete = useCallback( async (id: string) => { - if (!confirm(t("confirmDelete"))) return; setPendingDel(id); try { const fd = new FormData(); @@ -97,12 +172,62 @@ export function ManageSection(props: SharedProps) { toast.error(t("errorOccurred")); } setPendingDel(null); + setConfirmDel(null); }, [router, t], ); + const handleBulkDelete = useCallback(async () => { + if (!selected.size) return; + setBusyBulk(true); + try { + const ids = [...selected].map((s) => BigInt(s)); + await bulkDeletePermissions(ids); + toast.success(t("deleted")); + setSelected(new Set()); + router.refresh(); + } catch { + toast.error(t("errorOccurred")); + } + setBusyBulk(false); + setConfirmDel(null); + }, [selected, router, t]); + + const toggleSelect = useCallback((id: string) => { + setSelected((prev) => { + const next = new Set(prev); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); + }, []); + + const toggleAll = useCallback(() => { + if (selected.size === paginated.length) { + setSelected(new Set()); + } else { + setSelected(new Set(paginated.map((p) => String(p.id)))); + } + }, [paginated, selected]); + return (
+ + confirmDel === "__bulk__" + ? handleBulkDelete() + : handleDelete(confirmDel!) + } + onCancel={() => setConfirmDel(null)} + /> +
@@ -141,6 +266,7 @@ export function ManageSection(props: SharedProps) { {t("addPermission")}
{ e.preventDefault(); handleUpsert(new FormData(e.currentTarget)); @@ -188,12 +314,24 @@ export function ManageSection(props: SharedProps) {
-

- {t("permissions")}{" "} - - {filtered.length} - -

+
+

+ {t("permissions")}{" "} + + {filtered.length} + +

+ {selected.size > 0 && ( + + )} +
{filtered.length === 0 ? (
{t("noPermissions")}
) : ( @@ -201,6 +339,16 @@ export function ManageSection(props: SharedProps) { + @@ -211,100 +359,110 @@ export function ManageSection(props: SharedProps) { - {paginated.map((p, i) => ( - - - - - - + + + + + + + + - - - - ))} + + + ); + })}
+ 0 && + selected.size === paginated.length + } + onChange={toggleAll} + /> + # {t("colPermission")} {t("colDescription")}
- {(safePage - 1) * PAGE_SIZE + i + 1} - - {p.permission} - {p.description || "\u2014"} - {p.groupName ? ( - - {p.groupName} - - ) : ( - \u2014 - )} - - { - e.preventDefault(); - handleUpsert(new FormData(e.currentTarget)); - }} - style={{ display: "flex", gap: "0.5rem" }} - > + {paginated.map((p, i) => { + const sid = String(p.id); + return ( +
- - - - toggleSelect(sid)} /> + + {(safePage - 1) * PAGE_SIZE + i + 1} + + {p.permission} + {p.description || "\u2014"} + {p.groupName ? ( + + {p.groupName} + + ) : ( + \u2014 + )} + + { + e.preventDefault(); + handleUpsert(new FormData(e.currentTarget)); + }} + style={{ display: "flex", gap: "0.5rem" }} + > + + + + + + + + + {p.dependsOn ? ( + + {p.dependsOn} + {!props.permSet.has(p.dependsOn) ? " " + t("missing") : ""} + + ) : ( + \u2014 + )} + - - - {p.dependsOn ? ( - - {p.dependsOn} - {!props.permSet.has(p.dependsOn) ? " " + t("missing") : ""} - - ) : ( - \u2014 - )} - - -
@@ -337,10 +495,13 @@ export function ManageSection(props: SharedProps) { ); } +/* ────────── Presets Section ────────── */ + export function PresetsSection() { const t = useTranslations("pages.admin.housekeeping"); const router = useRouter(); const [busy, setBusy] = useState(null); + const [confirmClear, setConfirmClear] = useState(false); const handleApplyPreset = useCallback( async (preset: string) => { @@ -360,7 +521,6 @@ export function PresetsSection() { ); const handleClearAll = useCallback(async () => { - if (!confirm(t("confirmClearAll"))) return; setBusy("__clear__"); try { await clearAllPermissions(); @@ -370,10 +530,19 @@ export function PresetsSection() { toast.error(t("errorOccurred")); } setBusy(null); + setConfirmClear(false); }, [router, t]); return (
+ setConfirmClear(false)} + /> +

{t("presets")}

{t("presetsHint")} @@ -410,7 +579,7 @@ export function PresetsSection() {

); } + +/* ────────── Audit Section ────────── */ + +interface AuditEntry { + id: number; + userId: number; + username: string | null; + action: string; + target: string; + targetId: number | null; + before: unknown; + after: unknown; + createdAt: string; +} + +interface AuditSectionProps { + initialLogs: { + rows: AuditEntry[]; + total: number; + page: number; + perPage: number; + lastPage: number; + } | null; +} + +export function AuditSection({ initialLogs }: AuditSectionProps) { + const t = useTranslations("pages.admin.housekeeping"); + const router = useRouter(); + + if (!initialLogs || initialLogs.rows.length === 0) { + return ( +
+

{t("auditTitle")}

+

+ {t("auditHint")} +

+
+

{t("auditLogsAt")}

+ +
+
+ ); + } + + return ( +
+

{t("auditTitle")}

+

+ {t("auditHint")} +

+
+ + + + + + + + + + + {initialLogs.rows.map((log) => ( + + + + + + + ))} + +
{t("auditTime")}{t("auditUser")}{t("auditAction")}{t("auditTarget")}
+ {new Date(log.createdAt).toLocaleString()} + {log.username ?? "System"}{log.action} + {log.target} + {log.targetId != null ? ` #${log.targetId}` : ""} +
+
+
+ {t("auditLogsAt")}{" "} + +
+
+ ); +} diff --git a/src/app/admin/housekeeping/page.tsx b/src/app/admin/housekeeping/page.tsx index 1b4286cd..876b011d 100644 --- a/src/app/admin/housekeeping/page.tsx +++ b/src/app/admin/housekeeping/page.tsx @@ -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 (
@@ -308,20 +315,7 @@ export default async function AdminHousekeeping({ )} - {tab === "audit" && ( -
-

{t("auditTitle")}

-

- {t("auditHint")} -

-
-

{t("auditLogsAt")}

- - {t("viewAuditLogs")} - -
-
- )} + {tab === "audit" && }
); } diff --git a/src/messages/bg.json b/src/messages/bg.json index ad8da3f1..03f3b655 100644 --- a/src/messages/bg.json +++ b/src/messages/bg.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Стаи", diff --git a/src/messages/cs.json b/src/messages/cs.json index 408b8a32..f196b986 100644 --- a/src/messages/cs.json +++ b/src/messages/cs.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Pokoje", diff --git a/src/messages/da.json b/src/messages/da.json index 60e3925a..b577d654 100644 --- a/src/messages/da.json +++ b/src/messages/da.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Værelser", diff --git a/src/messages/de.json b/src/messages/de.json index c7f0e0b6..9b5603bf 100644 --- a/src/messages/de.json +++ b/src/messages/de.json @@ -1922,7 +1922,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Räume", diff --git a/src/messages/el.json b/src/messages/el.json index 73019c5d..ce40b4bd 100644 --- a/src/messages/el.json +++ b/src/messages/el.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Δωμάτια", diff --git a/src/messages/en.json b/src/messages/en.json index 3b7209b3..c82ed924 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -1895,6 +1895,12 @@ "cancel": "Cancel" }, "confirmClearAll": "Delete ALL permissions? This action cannot be undone!", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", "colGroup": "Group", "colDepends": "Depends on", "colPermission": "Permission", @@ -1957,7 +1963,11 @@ "auditTitle": "Permission audit log", "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", - "viewAuditLogs": "View audit logs" + "viewAuditLogs": "View audit logs", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Rooms", diff --git a/src/messages/es.json b/src/messages/es.json index e28c58a7..82b7467b 100644 --- a/src/messages/es.json +++ b/src/messages/es.json @@ -1922,7 +1922,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Salas", diff --git a/src/messages/fr.json b/src/messages/fr.json index fff186db..919b2006 100644 --- a/src/messages/fr.json +++ b/src/messages/fr.json @@ -1922,7 +1922,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Salons", diff --git a/src/messages/hr.json b/src/messages/hr.json index 4547586c..15e969fa 100644 --- a/src/messages/hr.json +++ b/src/messages/hr.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Sobe", diff --git a/src/messages/hu.json b/src/messages/hu.json index 0c7c32cf..8317cbe8 100644 --- a/src/messages/hu.json +++ b/src/messages/hu.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Szobák", diff --git a/src/messages/it.json b/src/messages/it.json index 44600013..864d28a9 100644 --- a/src/messages/it.json +++ b/src/messages/it.json @@ -1922,7 +1922,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Stanze", diff --git a/src/messages/nl.json b/src/messages/nl.json index acda7ef5..83271626 100644 --- a/src/messages/nl.json +++ b/src/messages/nl.json @@ -1895,6 +1895,12 @@ "cancel": "Annuleren" }, "confirmClearAll": "ALLE permissies verwijderen? Dit kan niet ongedaan worden gemaakt!", + "confirmClearAllDesc": "Dit verwijdert alle permissies uit de database. Weet je het zeker?", + "confirmDeletePermission": "Deze permissie permanent verwijderen?", + "confirmBulkDelete": "{count} geselecteerde permissies verwijderen?", + "deleteSelected": "Verwijder {count} geselecteerd", + "cancel": "Annuleren", + "confirm": "Bevestigen", "colGroup": "Groep", "colDepends": "Afhankelijk van", "colPermission": "Permissie", @@ -1957,7 +1963,11 @@ "auditTitle": "Permissie auditlog", "auditHint": "Alle wijzigingen aan housekeeping permissies worden gelogd.", "auditLogsAt": "Auditlogs zijn beschikbaar op de Auditlog-pagina.", - "viewAuditLogs": "Bekijk auditlogs" + "viewAuditLogs": "Bekijk auditlogs", + "auditTime": "Tijd", + "auditUser": "Gebruiker", + "auditAction": "Actie", + "auditTarget": "Doel" }, "rooms": { "title": "Kamers", diff --git a/src/messages/no.json b/src/messages/no.json index 604bf64e..45c8647d 100644 --- a/src/messages/no.json +++ b/src/messages/no.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Rom", diff --git a/src/messages/pl.json b/src/messages/pl.json index f4910cde..fa80c34f 100644 --- a/src/messages/pl.json +++ b/src/messages/pl.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Pokoje", diff --git a/src/messages/pt.json b/src/messages/pt.json index 35f16103..995595de 100644 --- a/src/messages/pt.json +++ b/src/messages/pt.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Quartos", diff --git a/src/messages/ro.json b/src/messages/ro.json index 0ea46c0c..a8e08d08 100644 --- a/src/messages/ro.json +++ b/src/messages/ro.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Camerele", diff --git a/src/messages/ru.json b/src/messages/ru.json index 4ee55434..b3f60e41 100644 --- a/src/messages/ru.json +++ b/src/messages/ru.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Rooms", diff --git a/src/messages/sk.json b/src/messages/sk.json index 2517d331..6b5cb550 100644 --- a/src/messages/sk.json +++ b/src/messages/sk.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Izby", diff --git a/src/messages/sr.json b/src/messages/sr.json index 2b012fbe..2f2df427 100644 --- a/src/messages/sr.json +++ b/src/messages/sr.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Собе", diff --git a/src/messages/sv.json b/src/messages/sv.json index 0511378e..1927f454 100644 --- a/src/messages/sv.json +++ b/src/messages/sv.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Rum", diff --git a/src/messages/tr.json b/src/messages/tr.json index 03de1c90..4dfcd204 100644 --- a/src/messages/tr.json +++ b/src/messages/tr.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Odalar", diff --git a/src/messages/uk.json b/src/messages/uk.json index 48c1d3d2..142a6d8d 100644 --- a/src/messages/uk.json +++ b/src/messages/uk.json @@ -1958,7 +1958,17 @@ "auditHint": "All changes to housekeeping permissions are logged.", "auditLogsAt": "Audit logs are available on the Audit log page.", "viewAuditLogs": "View audit logs", - "importedWithErrors": "Imported {count} permissions with {errors} errors" + "importedWithErrors": "Imported {count} permissions with {errors} errors", + "confirmClearAllDesc": "This will remove every permission entry from the database. Are you sure?", + "confirmDeletePermission": "Delete this permission permanently?", + "confirmBulkDelete": "Delete {count} selected permissions?", + "deleteSelected": "Delete {count} selected", + "cancel": "Cancel", + "confirm": "Confirm", + "auditTime": "Time", + "auditUser": "User", + "auditAction": "Action", + "auditTarget": "Target" }, "rooms": { "title": "Кімнати",