feat(admin): add restore dismissed alerts flow
Some checks failed
Test / vitest (push) Successful in 11m48s
Test / playwright (push) Failing after 9m50s
Test / visual (push) Failing after 9m19s
Test / Notify on failure (push) Successful in 2s

Admins can now surface dismissed alert types without waiting for the
underlying data to change. Adds a collapsible "Restore dismissed"
section below the active alerts with per-type checkboxes.

- ALERT_METADATA map in adminAlerts.js as the single source of truth
  for slug → title/severity; detectors refactored to reference it
- GET /api/admin/alerts/dismissed returns this admin's dismissals
  joined with metadata (title, severity, dismissedAt)
- POST /api/admin/alerts/restore deletes dismissals by alertType[],
  returns the deleted count
- AdminAlertsPanel fetches both active + dismissed; stays visible
  when either is non-empty; checkboxes + "Restore selected" button
- adminAlertRestoreSchema validates the POST body against the enum
- Auth guards test covers both new routes
This commit is contained in:
Jennie Robinson Faber 2026-04-08 12:22:35 +01:00
parent a2af4e31ff
commit 92e7dae74c
7 changed files with 423 additions and 41 deletions

View file

@ -0,0 +1,23 @@
import AdminAlertDismissal from '../../../models/adminAlertDismissal.js'
import { ALERT_METADATA } from '../../../utils/adminAlerts.js'
import { connectDB } from '../../../utils/mongoose.js'
export default defineEventHandler(async (event) => {
const admin = await requireAdmin(event)
await connectDB()
const rows = await AdminAlertDismissal.find({ adminId: admin._id.toString() })
.sort({ dismissedAt: -1 })
.lean()
const dismissed = rows
.filter((r) => ALERT_METADATA[r.alertType]) // defensive: skip any orphaned legacy slugs
.map((r) => ({
alertType: r.alertType,
title: ALERT_METADATA[r.alertType].title,
severity: ALERT_METADATA[r.alertType].severity,
dismissedAt: r.dismissedAt
}))
return { dismissed }
})

View file

@ -0,0 +1,15 @@
import AdminAlertDismissal from '../../../models/adminAlertDismissal.js'
import { connectDB } from '../../../utils/mongoose.js'
export default defineEventHandler(async (event) => {
const admin = await requireAdmin(event)
const { alertTypes } = await validateBody(event, adminAlertRestoreSchema)
await connectDB()
const result = await AdminAlertDismissal.deleteMany({
adminId: admin._id.toString(),
alertType: { $in: alertTypes }
})
return { ok: true, restored: result.deletedCount ?? 0 }
})