Make forced-delete dependency chips clickable to pivot the audit log

Task #134: Admins investigating a forced deletion can now click any
dependency chip on a force_delete row to jump to a pre-filtered audit log
view of the related history.

Backend (artifacts/api-server, lib/api-spec):
- Added targetType + targetId query params to GET /api/admin/audit-logs
  and its CSV export. targetId is validated as a positive integer (400
  on bad input). Codegen regenerated for the React API client.

Frontend (artifacts/tx-os/src/pages/admin.tsx):
- Dependency chips on forced-delete rows are now real <button> elements
  with aria-labels and keyboard focus. Non-deletion rows are unchanged.
- Chip → pivot mapping: groupCount→targetType=group,
  memberCount→targetType=user, appCount→targetType=app,
  roleCount→targetType=role; cascade chips (orderCount, messageCount,
  noteCount, etc.) pivot to the parent (targetType+targetId).
- Active filter is reflected in the URL hash (deep-linkable + reload
  safe) and shown as a dismissible pill in the panel; the pill includes
  a Clear button. Switching audit sub-section drops the filter.
- Section sync logic preserves hash params and uses a one-shot
  skipNextSectionSync ref so initial deep-linked hashes aren't clobbered.
- New i18n keys in en.json and ar.json for filter labels and chip
  aria-labels.

Tests:
- New backend tests in artifacts/api-server/tests/audit-logs-target-filter.test.mjs
  cover targetType narrowing, targetType+targetId narrowing, invalid
  targetId rejection, combination with forcedOnly, and CSV export
  honoring the new filters (7 tests, all passing).
- Verified end-to-end via the browser testing skill: chip click,
  filter pill, clear, deep-link reload all behave correctly.

Pre-existing unrelated failures (not touched): two PDF archive tests in
executive-meetings.test.mjs and the matching typecheck errors in
executive-meetings.ts.

Replit-Task-Id: 46f972ef-2874-4fc3-95c5-53d0ff0732e9
This commit is contained in:
riyadhafraa
2026-04-30 07:25:16 +00:00
parent d72c5cc851
commit 058cb8b817
8 changed files with 560 additions and 20 deletions
+26
View File
@@ -2434,6 +2434,19 @@ export const ListAuditLogsQueryParams = zod.object({
.optional()
.describe("Start date (inclusive, YYYY-MM-DD UTC)."),
to: zod.date().optional().describe("End date (inclusive, YYYY-MM-DD UTC)."),
targetType: zod.coerce
.string()
.optional()
.describe(
'Restrict results to entries whose `target_type` exactly matches\n(e.g. \"group\", \"app\", \"role\", \"user\", \"service\", \"settings\").\nCombines with `targetId` and the other filters.\n',
),
targetId: zod.coerce
.number()
.min(1)
.optional()
.describe(
"Restrict results to entries whose `target_id` exactly matches.\nTypically used together with `targetType` to focus on the history\nof a single entity.\n",
),
limit: zod.coerce
.number()
.min(1)
@@ -2504,4 +2517,17 @@ export const ExportAuditLogsCsvQueryParams = zod.object({
.optional()
.describe("Start date (inclusive, YYYY-MM-DD UTC)."),
to: zod.date().optional().describe("End date (inclusive, YYYY-MM-DD UTC)."),
targetType: zod.coerce
.string()
.optional()
.describe(
"Restrict the export to entries whose `target_type` exactly matches.\nCombines with `targetId` and the other filters.\n",
),
targetId: zod.coerce
.number()
.min(1)
.optional()
.describe(
"Restrict the export to entries whose `target_id` exactly matches.\n",
),
});