feat(alerts): always-visible dismiss/ack actions + Dismiss all (service, endpoint, UI)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,6 +120,42 @@ export async function dismissAlert(alertId: string, portId: string, userId: stri
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk-dismiss every open (non-dismissed, non-resolved) alert for a port,
|
||||
* optionally narrowed to a single rule and/or severity. Returns the count
|
||||
* dismissed. Port-scoped so it can never touch another tenant's alerts.
|
||||
*/
|
||||
export async function dismissAllForPort(
|
||||
portId: string,
|
||||
userId: string,
|
||||
filter: { ruleId?: AlertRuleId; severity?: AlertSeverity } = {},
|
||||
): Promise<number> {
|
||||
const conds = [eq(alerts.portId, portId), isNull(alerts.dismissedAt), isNull(alerts.resolvedAt)];
|
||||
if (filter.ruleId) conds.push(eq(alerts.ruleId, filter.ruleId));
|
||||
if (filter.severity) conds.push(eq(alerts.severity, filter.severity));
|
||||
|
||||
const rows = await db
|
||||
.update(alerts)
|
||||
.set({ dismissedAt: sql`now()`, dismissedBy: userId })
|
||||
.where(and(...conds))
|
||||
.returning({ id: alerts.id });
|
||||
|
||||
for (const r of rows) {
|
||||
emitToRoom(`port:${portId}`, 'alert:dismissed', { alertId: r.id, portId });
|
||||
}
|
||||
if (rows.length > 0) {
|
||||
void createAuditLog({
|
||||
portId,
|
||||
userId,
|
||||
action: 'update',
|
||||
entityType: 'alert',
|
||||
entityId: portId, // port-wide bulk action — no single alert subject
|
||||
metadata: { kind: 'dismiss_all', count: rows.length, filter },
|
||||
});
|
||||
}
|
||||
return rows.length;
|
||||
}
|
||||
|
||||
export async function acknowledgeAlert(
|
||||
alertId: string,
|
||||
portId: string,
|
||||
|
||||
Reference in New Issue
Block a user