From d02b9ef7ff2f9136a55298547a0339d7507aa86c Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 20 May 2026 14:28:35 +0100 Subject: [PATCH] Bind alert notification form labels --- .../Alerts/EmailProviderSelect.test.tsx | 20 ++++++ .../components/Alerts/EmailProviderSelect.tsx | 68 ++++++++++++++++--- .../AlertAppriseDestinationsSection.test.tsx | 59 ++++++++++++++++ .../AlertAppriseDestinationsSection.tsx | 48 ++++++++++--- 4 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 frontend-modern/src/features/alerts/AlertAppriseDestinationsSection.test.tsx diff --git a/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx b/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx index 4f7a06945d..a653527324 100644 --- a/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx +++ b/frontend-modern/src/components/Alerts/EmailProviderSelect.test.tsx @@ -133,6 +133,26 @@ describe('EmailProviderSelect', () => { ); }); + it('associates visible labels with manual SMTP fields', () => { + render(() => ( + + )); + + expect(screen.getByRole('textbox', { name: 'SMTP server' })).toBeInTheDocument(); + expect(screen.getByRole('spinbutton', { name: 'SMTP port' })).toBeInTheDocument(); + expect(screen.getByRole('textbox', { name: 'From address' })).toBeInTheDocument(); + expect(screen.getByRole('textbox', { name: 'Reply-to address' })).toBeInTheDocument(); + expect(screen.getByRole('textbox', { name: 'Username' })).toBeInTheDocument(); + expect(screen.getByLabelText('Password / API key')).toHaveAttribute('type', 'password'); + expect(screen.getByRole('textbox', { name: 'Recipients (one per line)' })).toBeInTheDocument(); + + fireEvent.click(screen.getByText('Show advanced options')); + + expect(screen.getByRole('spinbutton', { name: 'Rate limit' })).toBeInTheDocument(); + expect(screen.getByRole('spinbutton', { name: 'Max retries' })).toBeInTheDocument(); + expect(screen.getByRole('spinbutton', { name: 'Retry delay (seconds)' })).toBeInTheDocument(); + }); + it('loads providers from the API and populates the select', async () => { render(() => ( diff --git a/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx b/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx index 9e041a0e45..53f0575ecc 100644 --- a/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx +++ b/frontend-modern/src/components/Alerts/EmailProviderSelect.tsx @@ -1,4 +1,4 @@ -import { Show, For } from 'solid-js'; +import { Show, For, createUniqueId } from 'solid-js'; import type { UIEmailConfig } from '@/features/alerts/types'; import { ALERT_EMAIL_FROM_ADDRESS_LABEL, @@ -46,6 +46,19 @@ interface EmailProviderSelectProps extends EmailProviderSelectStateProps { export function EmailProviderSelect(props: EmailProviderSelectProps) { const state = useEmailProviderSelectState(props); + const fieldIdPrefix = `alert-email-${createUniqueId()}`; + const fieldIds = { + smtpServer: `${fieldIdPrefix}-smtp-server`, + smtpPort: `${fieldIdPrefix}-smtp-port`, + fromAddress: `${fieldIdPrefix}-from-address`, + replyTo: `${fieldIdPrefix}-reply-to`, + username: `${fieldIdPrefix}-username`, + password: `${fieldIdPrefix}-password`, + recipients: `${fieldIdPrefix}-recipients`, + rateLimit: `${fieldIdPrefix}-rate-limit`, + maxRetries: `${fieldIdPrefix}-max-retries`, + retryDelay: `${fieldIdPrefix}-retry-delay`, + }; const instructionBoxClass = 'mt-2 rounded border border-blue-200 bg-blue-50 px-3 py-2 text-xs leading-relaxed text-blue-900 dark:border-blue-700 dark:bg-blue-900 dark:text-blue-200'; @@ -103,8 +116,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {
- + props.onChange({ ...props.config, server: e.currentTarget.value })} @@ -114,8 +130,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {
- +
- + props.onChange({ ...props.config, from: e.currentTarget.value })} @@ -150,8 +172,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {
- + props.onChange({ ...props.config, replyTo: e.currentTarget.value })} @@ -161,8 +186,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {
- + props.onChange({ ...props.config, username: e.currentTarget.value })} @@ -172,8 +200,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {
- + props.onChange({ ...props.config, password: e.currentTarget.value })} @@ -184,8 +215,11 @@ export function EmailProviderSelect(props: EmailProviderSelectProps) {
- +