Skip to content

Commit 73a2469

Browse files
authored
[ResponseOps][MaintenanceWindows] Fix startDate not forwarded to custom recurrence component (elastic#223949)
## Summary - Forwards `startDate` correctly to the `CustomRecurringSchedule` component. The missing prop caused the monthly custom frequency sub-options to not show up. - Fixes the `CustomRecurringSchedule` component type to correctly reflect the required prop. - Removes the `custom-recurring-form` data test subject from the `<CustomRecurringSchedule>` JSX tag. The test subject wasn't forwarded to any DOM element, but the only test with an assertion using that test subject was passing because it was checking its absence (`not.toBeInTheDocument()`). ## Verification steps 1. Open the Maintenance Window creation page 2. Toggle "Repeat" on 3. In the recurrence form, check that all the custom frequencies work, showing the correct sub-options
1 parent d017a33 commit 73a2469

File tree

4 files changed

+156
-131
lines changed

4 files changed

+156
-131
lines changed

src/platform/packages/shared/response-ops/recurring-schedule-form/components/custom_recurring_schedule.test.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const TestWrapper = ({ children, iv = initialValue }: PropsWithChildren<{ iv?: F
3737
return <Form form={form}>{children}</Form>;
3838
};
3939

40+
const startDate = new Date().toISOString();
41+
4042
describe('CustomRecurringSchedule', () => {
4143
beforeEach(() => {
4244
jest.clearAllMocks();
@@ -45,7 +47,7 @@ describe('CustomRecurringSchedule', () => {
4547
it('renders all form fields', async () => {
4648
render(
4749
<TestWrapper>
48-
<CustomRecurringSchedule />
50+
<CustomRecurringSchedule startDate={startDate} />
4951
</TestWrapper>
5052
);
5153

@@ -58,7 +60,7 @@ describe('CustomRecurringSchedule', () => {
5860
it('renders byweekday field if custom frequency = weekly', async () => {
5961
render(
6062
<TestWrapper>
61-
<CustomRecurringSchedule />
63+
<CustomRecurringSchedule startDate={startDate} />
6264
</TestWrapper>
6365
);
6466

@@ -83,7 +85,7 @@ describe('CustomRecurringSchedule', () => {
8385
};
8486
render(
8587
<TestWrapper iv={iv}>
86-
<CustomRecurringSchedule />
88+
<CustomRecurringSchedule startDate={startDate} />
8789
</TestWrapper>
8890
);
8991

@@ -93,7 +95,7 @@ describe('CustomRecurringSchedule', () => {
9395
it('renders bymonth field if custom frequency = monthly', async () => {
9496
render(
9597
<TestWrapper>
96-
<CustomRecurringSchedule />
98+
<CustomRecurringSchedule startDate={startDate} />
9799
</TestWrapper>
98100
);
99101

@@ -111,7 +113,7 @@ describe('CustomRecurringSchedule', () => {
111113
it('should initialize the form when no initialValue provided', () => {
112114
render(
113115
<TestWrapper>
114-
<CustomRecurringSchedule />
116+
<CustomRecurringSchedule startDate={startDate} />
115117
</TestWrapper>
116118
);
117119

@@ -139,7 +141,7 @@ describe('CustomRecurringSchedule', () => {
139141
};
140142
render(
141143
<TestWrapper iv={iv}>
142-
<CustomRecurringSchedule />
144+
<CustomRecurringSchedule startDate={startDate} />
143145
</TestWrapper>
144146
);
145147

src/platform/packages/shared/response-ops/recurring-schedule-form/components/custom_recurring_schedule.tsx

Lines changed: 119 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* License v3.0 only", or the "Server Side Public License, v 1".
88
*/
99

10-
import React, { useMemo } from 'react';
10+
import React, { memo, useMemo } from 'react';
1111
import { Frequency } from '@kbn/rrule';
1212
import moment from 'moment';
1313
import { css } from '@emotion/react';
@@ -42,136 +42,134 @@ const styles = {
4242
};
4343

4444
export interface CustomRecurringScheduleProps {
45-
startDate?: string;
45+
startDate: string;
4646
}
4747

48-
export const CustomRecurringSchedule: React.FC = React.memo(
49-
({ startDate }: CustomRecurringScheduleProps) => {
50-
const [{ recurringSchedule }] = useFormData<{ recurringSchedule: RecurringSchedule }>({
51-
watch: [
52-
'recurringSchedule.frequency',
53-
'recurringSchedule.interval',
54-
'recurringSchedule.customFrequency',
55-
],
56-
});
48+
export const CustomRecurringSchedule = memo(({ startDate }: CustomRecurringScheduleProps) => {
49+
const [{ recurringSchedule }] = useFormData<{ recurringSchedule: RecurringSchedule }>({
50+
watch: [
51+
'recurringSchedule.frequency',
52+
'recurringSchedule.interval',
53+
'recurringSchedule.customFrequency',
54+
],
55+
});
5756

58-
const parsedSchedule = useMemo(() => {
59-
return parseSchedule(recurringSchedule);
60-
}, [recurringSchedule]);
57+
const parsedSchedule = useMemo(() => {
58+
return parseSchedule(recurringSchedule);
59+
}, [recurringSchedule]);
6160

62-
const frequencyOptions = useMemo(
63-
() => RECURRING_SCHEDULE_FORM_CUSTOM_FREQUENCY(parsedSchedule?.interval),
64-
[parsedSchedule?.interval]
65-
);
61+
const frequencyOptions = useMemo(
62+
() => RECURRING_SCHEDULE_FORM_CUSTOM_FREQUENCY(parsedSchedule?.interval),
63+
[parsedSchedule?.interval]
64+
);
6665

67-
const bymonthOptions = useMemo(() => {
68-
if (!startDate) return [];
69-
const date = moment(startDate);
70-
const { dayOfWeek, nthWeekdayOfMonth, isLastOfMonth } = getWeekdayInfo(date, 'ddd');
71-
return [
72-
{
73-
id: 'day',
74-
label: RECURRING_SCHEDULE_FORM_CUSTOM_REPEAT_MONTHLY_ON_DAY(date),
75-
},
76-
{
77-
id: 'weekday',
78-
label:
79-
RECURRING_SCHEDULE_FORM_WEEKDAY_SHORT(dayOfWeek)[isLastOfMonth ? 0 : nthWeekdayOfMonth],
80-
},
81-
];
82-
}, [startDate]);
66+
const bymonthOptions = useMemo(() => {
67+
if (!startDate) return [];
68+
const date = moment(startDate);
69+
const { dayOfWeek, nthWeekdayOfMonth, isLastOfMonth } = getWeekdayInfo(date, 'ddd');
70+
return [
71+
{
72+
id: 'day',
73+
label: RECURRING_SCHEDULE_FORM_CUSTOM_REPEAT_MONTHLY_ON_DAY(date),
74+
},
75+
{
76+
id: 'weekday',
77+
label:
78+
RECURRING_SCHEDULE_FORM_WEEKDAY_SHORT(dayOfWeek)[isLastOfMonth ? 0 : nthWeekdayOfMonth],
79+
},
80+
];
81+
}, [startDate]);
8382

84-
const defaultByWeekday = useMemo(() => getInitialByWeekday([], moment(startDate)), [startDate]);
83+
const defaultByWeekday = useMemo(() => getInitialByWeekday([], moment(startDate)), [startDate]);
8584

86-
return (
87-
<>
88-
{parsedSchedule?.frequency !== Frequency.DAILY ? (
89-
<>
90-
<EuiSpacer size="s" />
91-
<EuiFlexGroup gutterSize="s" alignItems="flexStart">
92-
<EuiFlexItem>
93-
<UseField
94-
path="recurringSchedule.interval"
95-
css={styles.flexField}
96-
componentProps={{
97-
'data-test-subj': 'interval-field',
98-
id: 'interval',
99-
euiFieldProps: {
100-
'data-test-subj': 'customRecurringScheduleIntervalInput',
101-
min: 1,
102-
prepend: (
103-
<EuiFormLabel htmlFor={'interval'}>
104-
{RECURRING_SCHEDULE_FORM_INTERVAL_EVERY}
105-
</EuiFormLabel>
106-
),
107-
},
108-
}}
109-
/>
110-
</EuiFlexItem>
111-
<EuiFlexItem>
112-
<UseField
113-
path="recurringSchedule.customFrequency"
114-
componentProps={{
115-
'data-test-subj': 'custom-frequency-field',
116-
euiFieldProps: {
117-
'data-test-subj': 'customRecurringScheduleFrequencySelect',
118-
options: frequencyOptions,
119-
},
120-
}}
121-
/>
122-
</EuiFlexItem>
123-
</EuiFlexGroup>
124-
<EuiSpacer size="s" />
125-
</>
126-
) : null}
127-
{Number(parsedSchedule?.customFrequency) === Frequency.WEEKLY ||
128-
parsedSchedule?.frequency === Frequency.DAILY ? (
129-
<UseField
130-
path="recurringSchedule.byweekday"
131-
config={{
132-
type: FIELD_TYPES.MULTI_BUTTON_GROUP,
133-
label: '',
134-
validations: [
135-
{
136-
validator: ({ value }) => {
137-
if (
138-
Object.values(value as MultiButtonGroupFieldValue).every((v) => v === false)
139-
) {
140-
return {
141-
message: RECURRING_SCHEDULE_FORM_BYWEEKDAY_REQUIRED,
142-
};
143-
}
85+
return (
86+
<>
87+
{parsedSchedule?.frequency !== Frequency.DAILY ? (
88+
<>
89+
<EuiSpacer size="s" />
90+
<EuiFlexGroup gutterSize="s" alignItems="flexStart">
91+
<EuiFlexItem>
92+
<UseField
93+
path="recurringSchedule.interval"
94+
css={styles.flexField}
95+
componentProps={{
96+
'data-test-subj': 'interval-field',
97+
id: 'interval',
98+
euiFieldProps: {
99+
'data-test-subj': 'customRecurringScheduleIntervalInput',
100+
min: 1,
101+
prepend: (
102+
<EuiFormLabel htmlFor={'interval'}>
103+
{RECURRING_SCHEDULE_FORM_INTERVAL_EVERY}
104+
</EuiFormLabel>
105+
),
144106
},
107+
}}
108+
/>
109+
</EuiFlexItem>
110+
<EuiFlexItem>
111+
<UseField
112+
path="recurringSchedule.customFrequency"
113+
componentProps={{
114+
'data-test-subj': 'custom-frequency-field',
115+
euiFieldProps: {
116+
'data-test-subj': 'customRecurringScheduleFrequencySelect',
117+
options: frequencyOptions,
118+
},
119+
}}
120+
/>
121+
</EuiFlexItem>
122+
</EuiFlexGroup>
123+
<EuiSpacer size="s" />
124+
</>
125+
) : null}
126+
{Number(parsedSchedule?.customFrequency) === Frequency.WEEKLY ||
127+
parsedSchedule?.frequency === Frequency.DAILY ? (
128+
<UseField
129+
path="recurringSchedule.byweekday"
130+
config={{
131+
type: FIELD_TYPES.MULTI_BUTTON_GROUP,
132+
label: '',
133+
validations: [
134+
{
135+
validator: ({ value }) => {
136+
if (
137+
Object.values(value as MultiButtonGroupFieldValue).every((v) => v === false)
138+
) {
139+
return {
140+
message: RECURRING_SCHEDULE_FORM_BYWEEKDAY_REQUIRED,
141+
};
142+
}
145143
},
146-
],
147-
defaultValue: defaultByWeekday,
148-
}}
149-
componentProps={{
150-
'data-test-subj': 'byweekday-field',
151-
euiFieldProps: {
152-
'data-test-subj': 'customRecurringScheduleByWeekdayButtonGroup',
153-
legend: 'Repeat on weekday',
154-
options: WEEKDAY_OPTIONS,
155144
},
156-
}}
157-
/>
158-
) : null}
145+
],
146+
defaultValue: defaultByWeekday,
147+
}}
148+
componentProps={{
149+
'data-test-subj': 'byweekday-field',
150+
euiFieldProps: {
151+
'data-test-subj': 'customRecurringScheduleByWeekdayButtonGroup',
152+
legend: 'Repeat on weekday',
153+
options: WEEKDAY_OPTIONS,
154+
},
155+
}}
156+
/>
157+
) : null}
159158

160-
{Number(parsedSchedule?.customFrequency) === Frequency.MONTHLY ? (
161-
<UseField
162-
path="recurringSchedule.bymonth"
163-
componentProps={{
164-
'data-test-subj': 'bymonth-field',
165-
euiFieldProps: {
166-
legend: 'Repeat on weekday or month day',
167-
options: bymonthOptions,
168-
},
169-
}}
170-
/>
171-
) : null}
172-
</>
173-
);
174-
}
175-
);
159+
{Number(parsedSchedule?.customFrequency) === Frequency.MONTHLY ? (
160+
<UseField
161+
path="recurringSchedule.bymonth"
162+
componentProps={{
163+
'data-test-subj': 'bymonth-field',
164+
euiFieldProps: {
165+
legend: 'Repeat on weekday or month day',
166+
options: bymonthOptions,
167+
},
168+
}}
169+
/>
170+
) : null}
171+
</>
172+
);
173+
});
176174

177175
CustomRecurringSchedule.displayName = 'CustomRecurringSchedule';

src/platform/packages/shared/response-ops/recurring-schedule-form/components/recurring_schedule_form_fields.test.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type { RecurringSchedule } from '../types';
1818
import { Form, useForm } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
1919
import { getRecurringScheduleFormSchema } from '../schemas/recurring_schedule_form_schema';
2020
import { RecurrenceEnd } from '../constants';
21+
import { Frequency } from '@kbn/rrule';
2122

2223
const baseProps: RecurringScheduleFieldsProps = {
2324
startDate: '2023-03-24',
@@ -29,7 +30,7 @@ interface FormValue {
2930

3031
const initialValue: FormValue = {
3132
recurringSchedule: {
32-
frequency: 'CUSTOM',
33+
frequency: Frequency.WEEKLY,
3334
ends: RecurrenceEnd.NEVER,
3435
},
3536
};
@@ -57,7 +58,7 @@ describe('RecurringScheduleForm', () => {
5758
);
5859

5960
expect(screen.getByTestId('frequency-field')).toBeInTheDocument();
60-
expect(screen.queryByTestId('custom-recurring-form')).not.toBeInTheDocument();
61+
expect(screen.queryByTestId('customRecurringScheduleIntervalInput')).not.toBeInTheDocument();
6162
expect(screen.getByTestId('ends-field')).toBeInTheDocument();
6263
expect(screen.queryByTestId('until-field')).not.toBeInTheDocument();
6364
expect(screen.queryByTestId('count-field')).not.toBeInTheDocument();
@@ -88,4 +89,28 @@ describe('RecurringScheduleForm', () => {
8889
await userEvent.click(btn);
8990
expect(await screen.findByTestId('count-field')).toBeInTheDocument();
9091
});
92+
93+
it('renders custom schedule if frequency = daily', async () => {
94+
render(
95+
<TestWrapper
96+
iv={{ recurringSchedule: { frequency: Frequency.DAILY, ends: RecurrenceEnd.NEVER } }}
97+
>
98+
<RecurringScheduleFormFields {...baseProps} />
99+
</TestWrapper>
100+
);
101+
102+
expect(
103+
await screen.findByTestId('customRecurringScheduleByWeekdayButtonGroup')
104+
).toBeInTheDocument();
105+
});
106+
107+
it('renders custom schedule if frequency = custom', async () => {
108+
render(
109+
<TestWrapper iv={{ recurringSchedule: { frequency: 'CUSTOM', ends: RecurrenceEnd.NEVER } }}>
110+
<RecurringScheduleFormFields {...baseProps} />
111+
</TestWrapper>
112+
);
113+
114+
expect(await screen.findByTestId('customRecurringScheduleIntervalInput')).toBeInTheDocument();
115+
});
91116
});

src/platform/packages/shared/response-ops/recurring-schedule-form/components/recurring_schedule_form_fields.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const toMoment = (value: string): Moment => moment(value);
5959
export const toString = (value: Moment): string => value.toISOString();
6060

6161
export interface RecurringScheduleFieldsProps {
62-
startDate?: string;
62+
startDate: string;
6363
endDate?: string;
6464
timezone?: string[];
6565
allowInfiniteRecurrence?: boolean;
@@ -147,7 +147,7 @@ export const RecurringScheduleFormFields = memo(
147147
/>
148148
{(parsedSchedule?.frequency === Frequency.DAILY ||
149149
parsedSchedule?.frequency === 'CUSTOM') && (
150-
<CustomRecurringSchedule data-test-subj="custom-recurring-form" />
150+
<CustomRecurringSchedule startDate={startDate} />
151151
)}
152152
<UseField
153153
path="recurringSchedule.ends"

0 commit comments

Comments
 (0)