Skip to content

Commit 8c8d916

Browse files
upcoming: [DI-28503] - Add filter components for notification channel create flow (#13217)
* upcoming: [DI-28503] - Add components for notification channel create flow * upcoming: [DI-28503] - Add changeset * upcoming: [DI-28503] - PR comment * upcoming: [DI-28503] - Prefer complete user obj in recipient options, address comments
1 parent 218ab5e commit 8c8d916

File tree

6 files changed

+662
-0
lines changed

6 files changed

+662
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Upcoming Features
3+
---
4+
5+
CloudPulse-Alerts: Add components for create notification channel flow ([#13217](https://github.com/linode/manager/pull/13217))

packages/manager/src/featureFlags.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ interface AclpAlerting {
156156
alertDefinitions: boolean;
157157
beta: boolean;
158158
editDisabledStatuses?: AlertStatusType[];
159+
maxEmailChannelRecipients?: number;
159160
notificationChannels: boolean;
160161
recentActivity: boolean;
161162
systemChannelSupportedServices?: CloudPulseServiceType[]; // linode, dbaas, etc.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
import * as React from 'react';
4+
5+
import { renderWithTheme } from 'src/utilities/testHelpers';
6+
7+
import { channelTypeOptions } from '../../constants';
8+
import { NotificationChannelTypeSelect } from './NotificationChannelTypeSelect';
9+
10+
import type { NotificationChannelTypeSelectProps } from './NotificationChannelTypeSelect';
11+
12+
const mockHandleChannelTypeChange = vi.fn();
13+
const mockOnBlur = vi.fn();
14+
15+
const props: NotificationChannelTypeSelectProps = {
16+
handleChannelTypeChange: mockHandleChannelTypeChange,
17+
onBlur: mockOnBlur,
18+
options: channelTypeOptions,
19+
value: null,
20+
};
21+
22+
describe('NotificationChannelTypeSelect component tests', () => {
23+
it('should render the Autocomplete component', () => {
24+
renderWithTheme(<NotificationChannelTypeSelect {...props} />);
25+
26+
expect(screen.getByTestId('channel-type-select')).toBeVisible();
27+
expect(screen.getByText('Type')).toBeVisible();
28+
expect(screen.getByPlaceholderText('Select a Channel Type')).toBeVisible();
29+
});
30+
31+
it('should render channel type options when opened and able to select an option', async () => {
32+
renderWithTheme(<NotificationChannelTypeSelect {...props} />);
33+
34+
await userEvent.click(screen.getByRole('button', { name: 'Open' }));
35+
expect(await screen.findByRole('option', { name: 'Email' })).toBeVisible();
36+
37+
// select the email option
38+
await userEvent.click(await screen.findByRole('option', { name: 'Email' }));
39+
expect(screen.getByRole('combobox')).toHaveAttribute('value', 'Email');
40+
41+
// verify handleChannelTypeChange is called with the correct value
42+
expect(mockHandleChannelTypeChange).toHaveBeenCalledWith('email');
43+
});
44+
45+
it('should be able to clear the selected channel type', async () => {
46+
renderWithTheme(<NotificationChannelTypeSelect {...props} value="email" />);
47+
48+
// Verify initial value is set
49+
expect(screen.getByRole('combobox')).toHaveAttribute('value', 'Email');
50+
51+
// Click the clear button
52+
const clearButton = screen.getByLabelText('Clear');
53+
await userEvent.click(clearButton);
54+
55+
// verify handleChannelTypeChange is called with null
56+
expect(screen.getByRole('combobox')).toHaveAttribute('value', '');
57+
expect(mockHandleChannelTypeChange).toHaveBeenCalledWith(null);
58+
});
59+
60+
it('should display error message when error prop is provided', () => {
61+
const errorMessage = 'This field is required';
62+
63+
renderWithTheme(
64+
<NotificationChannelTypeSelect {...props} error={errorMessage} />
65+
);
66+
67+
expect(screen.getByText(errorMessage)).toBeVisible();
68+
});
69+
70+
it('should call onBlur when the field loses focus', async () => {
71+
renderWithTheme(<NotificationChannelTypeSelect {...props} />);
72+
73+
const combobox = screen.getByRole('combobox');
74+
await userEvent.click(combobox);
75+
await userEvent.tab();
76+
77+
expect(mockOnBlur).toHaveBeenCalled();
78+
});
79+
80+
it('should handle empty options array', async () => {
81+
renderWithTheme(<NotificationChannelTypeSelect {...props} options={[]} />);
82+
83+
expect(screen.getByTestId('channel-type-select')).toBeVisible();
84+
expect(screen.getByPlaceholderText('Select a Channel Type')).toBeVisible();
85+
86+
await userEvent.click(screen.getByRole('button', { name: 'Open' }));
87+
expect(
88+
screen.getByText('You have no options to choose from')
89+
).toBeVisible();
90+
});
91+
92+
it('should render with null value', async () => {
93+
renderWithTheme(<NotificationChannelTypeSelect {...props} value={null} />);
94+
95+
expect(screen.getByRole('combobox')).toHaveAttribute('value', '');
96+
});
97+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Autocomplete } from '@linode/ui';
2+
import React from 'react';
3+
4+
import type { Item } from '../../constants';
5+
import type { ChannelType } from '@linode/api-v4';
6+
7+
export interface NotificationChannelTypeSelectProps {
8+
/**
9+
* Error text to display when the field has a validation error
10+
*/
11+
error?: string;
12+
/**
13+
* Function to handle the change of the channel type
14+
*/
15+
handleChannelTypeChange: (value: ChannelType | null) => void;
16+
/**
17+
* Function to handle the blur event
18+
*/
19+
onBlur?: () => void;
20+
/**
21+
* Options for the channel type select
22+
*/
23+
options: Item<string, ChannelType>[];
24+
/**
25+
* Value of the channel type in the form
26+
*/
27+
value: ChannelType | null;
28+
}
29+
30+
export const NotificationChannelTypeSelect = React.memo(
31+
(props: NotificationChannelTypeSelectProps) => {
32+
const { error, handleChannelTypeChange, value, options, onBlur } = props;
33+
34+
return (
35+
<Autocomplete
36+
data-testid="channel-type-select"
37+
errorText={error}
38+
label="Type"
39+
onBlur={onBlur}
40+
onChange={(_, selected, reason) => {
41+
if (selected) {
42+
handleChannelTypeChange(selected.value);
43+
}
44+
if (reason === 'clear') {
45+
handleChannelTypeChange(null);
46+
}
47+
}}
48+
options={options}
49+
placeholder="Select a Channel Type"
50+
value={options.find((option) => option.value === value) ?? null}
51+
/>
52+
);
53+
}
54+
);

0 commit comments

Comments
 (0)