- Add GatedButton: buttons stay in the DOM (D-05) always, wrapped in a
Tooltip explanation when disabled
- Gate all three actions with hasPermission(role, 'phishing', 'approve'|
'remediate') from lib/permissions.ts — the identical check the server
routes enforce, never a bespoke role === 'admin' string check (REVIEW-06)
- Derive resolved = campaignStatus === 'false_positive' OR any completed
remediation_actions row; resolved-state tooltip mirrors the completed
action's approver/date or the campaign's updated_at
- Remediate: AlertDialog confirmation listing approved action count/types,
then POST /remediate (no body), refetch on success
- Mark as false positive: AlertDialog with optional reason Textarea, then
POST /mark-false-positive { reason? }; disabled reason mirrors the
server's 409 guard exactly (approved/completed remediation blocks it)