Skip to content

Commit 8c4eaaa

Browse files
authored
feat(alert): add support for alert email notification channel (#2327)
* feat(alert): adapt to new api for alerting * feat(alert): adapt support for email receveir * minor fix * fix: inline validation in notification-channel-modal.tsx
1 parent ba63f76 commit 8c4eaaa

5 files changed

Lines changed: 578 additions & 132 deletions

File tree

libs/domains/observability/feature/src/lib/alerting/alerting-creation-flow/metric-configuration-step/metric-configuration-step.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,8 @@ export function MetricConfigurationStep({
684684
label: (
685685
<span className="flex items-center gap-1">
686686
{match(receiver.type)
687-
.with('SLACK', (v) => <Icon name={v} width={14} height={14} />)
687+
.with('SLACK', () => <Icon name="SLACK" width={14} height={14} />)
688+
.with('EMAIL', () => <Icon iconName="envelope" iconStyle="regular" className="text-xs" />)
688689
.otherwise(() => (
689690
<Icon iconName="webhook" iconStyle="regular" className="text-xs" />
690691
))}

libs/domains/observability/feature/src/lib/alerting/notification-channel-modal/notification-channel-modal.spec.tsx

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type AlertReceiverResponse } from 'qovery-typescript-axios'
1+
import { type AlertReceiverResponse, type EmailAlertReceiverResponse } from 'qovery-typescript-axios'
22
import { renderWithProviders, screen } from '@qovery/shared/util-tests'
33
import * as useCreateAlertReceiver from '../../hooks/use-create-alert-receiver/use-create-alert-receiver'
44
import * as useEditAlertReceiver from '../../hooks/use-edit-alert-receiver/use-edit-alert-receiver'
@@ -90,7 +90,7 @@ describe('NotificationChannelModal', () => {
9090
send_resolved: true,
9191
organization_id: 'org-123',
9292
description: 'Webhook for Qovery alerts',
93-
webhook_url: undefined,
93+
webhook_url: '',
9494
},
9595
},
9696
})
@@ -117,4 +117,72 @@ describe('NotificationChannelModal', () => {
117117
payload: {},
118118
})
119119
})
120+
121+
describe('EMAIL receiver type', () => {
122+
const emailAlertReceiver: EmailAlertReceiverResponse = {
123+
id: 'email-receiver-123',
124+
name: 'Email Notifications',
125+
type: 'EMAIL',
126+
send_resolved: true,
127+
to: 'ops@example.com',
128+
from: 'alerts@example.com',
129+
smarthost: 'smtp.gmail.com:587',
130+
auth_username: 'alerts@example.com',
131+
require_tls: true,
132+
} as EmailAlertReceiverResponse
133+
134+
it('should render create mode with email fields', async () => {
135+
renderWithProviders(<NotificationChannelModal onClose={mockOnClose} organizationId="org-123" type="EMAIL" />)
136+
137+
expect(await screen.findByText('New email')).toBeInTheDocument()
138+
expect(await screen.findByLabelText('Display name')).toBeInTheDocument()
139+
expect(await screen.findByLabelText('To email')).toBeInTheDocument()
140+
expect(await screen.findByLabelText('From email')).toBeInTheDocument()
141+
expect(await screen.findByLabelText('SMTP Server')).toBeInTheDocument()
142+
expect(await screen.findByLabelText('SMTP Username')).toBeInTheDocument()
143+
expect(await screen.findByLabelText('SMTP Password')).toBeInTheDocument()
144+
expect(await screen.findByText('Require TLS')).toBeInTheDocument()
145+
})
146+
147+
it('should render edit mode with email fields pre-filled', async () => {
148+
renderWithProviders(
149+
<NotificationChannelModal onClose={mockOnClose} organizationId="org-123" alertReceiver={emailAlertReceiver} />
150+
)
151+
152+
expect(await screen.findByText('Edit email')).toBeInTheDocument()
153+
expect(await screen.findByDisplayValue('Email Notifications')).toBeInTheDocument()
154+
expect(await screen.findByDisplayValue('ops@example.com')).toBeInTheDocument()
155+
// Both "From email" and "SMTP Username" have the same value, so we check both exist
156+
const alertsEmails = await screen.findAllByDisplayValue('alerts@example.com')
157+
expect(alertsEmails).toHaveLength(2) // From email + SMTP Username
158+
expect(await screen.findByDisplayValue('smtp.gmail.com:587')).toBeInTheDocument()
159+
})
160+
161+
it('should send test notification with email payload in create mode', async () => {
162+
const mockValidateAlertReceiver = jest.fn()
163+
mockUseValidateAlertReceiver.mockReturnValue({
164+
mutate: mockValidateAlertReceiver,
165+
isLoading: false,
166+
})
167+
168+
const { userEvent } = renderWithProviders(
169+
<NotificationChannelModal onClose={mockOnClose} organizationId="org-123" type="EMAIL" />
170+
)
171+
172+
const testButton = await screen.findByText('Send test notification')
173+
await userEvent.click(testButton)
174+
175+
expect(mockValidateAlertReceiver).toHaveBeenCalledWith({
176+
payload: {
177+
alert_receiver: expect.objectContaining({
178+
type: 'EMAIL',
179+
name: 'Email notifications',
180+
send_resolved: true,
181+
organization_id: 'org-123',
182+
description: 'Email notifications for Qovery alerts',
183+
}),
184+
},
185+
})
186+
})
187+
})
120188
})

0 commit comments

Comments
 (0)