style(alerts): format warning preference repair

Resolve the PR2087 frontend formatting gate without changing severity behavior or rewriting the reviewed source. Re-run the production-component browser matrix and refresh its content hashes; whole-tree formatting and local TypeScript checking pass.

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot] 2026-09-14 22:46:12 +01:00
parent e8bbda6f71
commit 10d466e1a3
8 changed files with 55 additions and 30 deletions

View file

@ -2944,3 +2944,7 @@ preserve all three supported minimum-severity values: all, warning, critical.
Unknown values still fall back to all. The email adapter round-trip matrix and
webhook edit/save regression cover issue #2069 without altering delivery filters
or sending provider notifications. Component proof is not installed delivery.
Formatting-only follow-up retains this warning-level contract. The production-component
browser matrix was rerun after formatting at desktop and narrow widths, including
all/critical/warning save/reload, cancel, and warning webhook creation.

View file

@ -10836,3 +10836,7 @@ GET decoding and PUT encoding. Unknown inputs retain the all fallback. This
repairs a dropped supported value without introducing a new wire enum or changing
backend routing. The notification adapter save/reload matrix verifies each
supported severity in frontend-modern/src/api/__tests__/notifications.test.ts.
Formatting-only follow-up retains this warning-level contract. The production-component
browser matrix was rerun after formatting at desktop and narrow widths, including
all/critical/warning save/reload, cancel, and warning webhook creation.

View file

@ -918,3 +918,7 @@ from all and critical. A warning selection must not become all through frontend
normalization. Existing backend severity admission and delivery queues remain
unchanged. The notification API adapter round trips and WebhookConfig edit/save
regression establish frontend control preservation, not provider delivery.
Formatting-only follow-up retains this warning-level contract. The production-component
browser matrix was rerun after formatting at desktop and narrow widths, including
all/critical/warning save/reload, cancel, and warning webhook creation.

View file

@ -1,7 +1,7 @@
{
"version": 1,
"base_sha": "ce1e99ba4e37b735d22158ac74a93afa26d7611f",
"verified_at": "2026-09-14T21:33:45.967568Z",
"verified_at": "2026-09-14T21:45:40.182293Z",
"result": "passed",
"changed_paths": [
"frontend-modern/src/api/notifications.ts",
@ -9,9 +9,9 @@
"frontend-modern/src/components/Alerts/useWebhookConfigState.ts"
],
"content_sha256": {
"frontend-modern/src/api/notifications.ts": "6eb5080070913baa025b07ffef1c38f3297ddfce8095ff71b6297b7e2cf09892",
"frontend-modern/src/api/notifications.ts": "ed4d7dd4946ed2295dff919134f394d0139d270bb446d069f4ddc8a9784b1667",
"frontend-modern/src/components/Alerts/WebhookConfigList.tsx": "0830ab5c9f7e0173dbdf3e92ed0e0c9cbf0a34942edb58001a3220d43b39d6c3",
"frontend-modern/src/components/Alerts/useWebhookConfigState.ts": "e79778f3e0b85536c672509210a81d258f8f8e483d09f5ef295118d428cf7a70"
"frontend-modern/src/components/Alerts/useWebhookConfigState.ts": "b641c911baeda41adfbf82621ede005db2bdc032f25786d4533c422b59b64047"
},
"routes": [
"/browser-tests/severity.html"

View file

@ -425,19 +425,21 @@ describe('NotificationsAPI', () => {
});
});
describe('email minimum severity save/reload (#2069)', () => {
it.each(['all', 'warning', 'critical'] as const)('preserves %s through the API adapter', async (minimumSeverity) => {
const mock = vi.mocked(apiFetchJSON);
mock.mockReset();
mock.mockResolvedValueOnce({ minimumSeverity });
const loaded = await NotificationsAPI.getEmailConfig();
expect(loaded.minimumSeverity).toBe(minimumSeverity);
mock.mockResolvedValueOnce({ success: true });
await NotificationsAPI.updateEmailConfig(loaded);
const saved = JSON.parse(String(mock.mock.calls[1][1]?.body));
expect(saved.minimumSeverity).toBe(minimumSeverity);
mock.mockResolvedValueOnce(saved);
expect((await NotificationsAPI.getEmailConfig()).minimumSeverity).toBe(minimumSeverity);
});
it.each(['all', 'warning', 'critical'] as const)(
'preserves %s through the API adapter',
async (minimumSeverity) => {
const mock = vi.mocked(apiFetchJSON);
mock.mockReset();
mock.mockResolvedValueOnce({ minimumSeverity });
const loaded = await NotificationsAPI.getEmailConfig();
expect(loaded.minimumSeverity).toBe(minimumSeverity);
mock.mockResolvedValueOnce({ success: true });
await NotificationsAPI.updateEmailConfig(loaded);
const saved = JSON.parse(String(mock.mock.calls[1][1]?.body));
expect(saved.minimumSeverity).toBe(minimumSeverity);
mock.mockResolvedValueOnce(saved);
expect((await NotificationsAPI.getEmailConfig()).minimumSeverity).toBe(minimumSeverity);
},
);
});

View file

@ -437,7 +437,8 @@ export class NotificationsAPI {
if (typeof backendConfig.tagFilterMode === 'string') {
config.tagFilterMode = backendConfig.tagFilterMode === 'any' ? 'any' : 'all';
}
config.minimumSeverity = backendConfig.minimumSeverity === 'critical' || backendConfig.minimumSeverity === 'warning'
config.minimumSeverity =
backendConfig.minimumSeverity === 'critical' || backendConfig.minimumSeverity === 'warning'
? backendConfig.minimumSeverity
: 'all';
return config;
@ -469,9 +470,10 @@ export class NotificationsAPI {
backendConfig.tagFilterMode = config.tagFilterMode === 'any' ? 'any' : 'all';
}
if (config.minimumSeverity !== undefined) {
backendConfig.minimumSeverity = config.minimumSeverity === 'critical' || config.minimumSeverity === 'warning'
? config.minimumSeverity
: 'all';
backendConfig.minimumSeverity =
config.minimumSeverity === 'critical' || config.minimumSeverity === 'warning'
? config.minimumSeverity
: 'all';
}
return apiFetchJSON(`${this.baseUrl}/email`, {

View file

@ -714,12 +714,19 @@ describe('WebhookConfig', () => {
it('preserves warning severity when editing and saving a webhook', () => {
const webhook = makeWebhook({ minimumSeverity: 'warning' });
render(() => (
<WebhookConfig webhooks={[webhook]} onAdd={onAddMock} onUpdate={onUpdateMock}
onDelete={onDeleteMock} onTest={onTestMock} />
<WebhookConfig
webhooks={[webhook]}
onAdd={onAddMock}
onUpdate={onUpdateMock}
onDelete={onDeleteMock}
onTest={onTestMock}
/>
));
fireEvent.click(screen.getByText('Edit'));
fireEvent.click(screen.getByText('Update Webhook'));
expect(onUpdateMock).toHaveBeenCalledWith(expect.objectContaining({ minimumSeverity: 'warning' }));
expect(onUpdateMock).toHaveBeenCalledWith(
expect.objectContaining({ minimumSeverity: 'warning' }),
);
});
it('calls onUpdate with updated data when saving an edited webhook', () => {

View file

@ -185,9 +185,10 @@ export function useWebhookConfigState(props: WebhookConfigProps): WebhookConfigS
mention: webhook.mention || '',
tagFilter: webhook.tagFilter ?? [],
tagFilterMode: webhook.tagFilterMode === 'any' ? 'any' : 'all',
minimumSeverity: webhook.minimumSeverity === 'critical' || webhook.minimumSeverity === 'warning'
? webhook.minimumSeverity
: 'all',
minimumSeverity:
webhook.minimumSeverity === 'critical' || webhook.minimumSeverity === 'warning'
? webhook.minimumSeverity
: 'all',
});
const headers = webhook.headers || {};
@ -273,9 +274,10 @@ export function useWebhookConfigState(props: WebhookConfigProps): WebhookConfigS
mention: data.mention,
tagFilter: data.tagFilter ?? [],
tagFilterMode: data.tagFilterMode === 'any' ? 'any' : 'all',
minimumSeverity: data.minimumSeverity === 'critical' || data.minimumSeverity === 'warning'
? data.minimumSeverity
: 'all',
minimumSeverity:
data.minimumSeverity === 'critical' || data.minimumSeverity === 'warning'
? data.minimumSeverity
: 'all',
});
resetForm();
};