mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.17] [Response Ops] Fix maintenance window custom schedule create and update error (#192649) (#208335)
# Backport This will backport the following commits from `main` to `8.17`: - [[Response Ops] Fix maintenance window custom schedule create and update error (#192649)](https://github.com/elastic/kibana/pull/192649) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Jiawei Wu","email":"74562234+JiaweiWu@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-09-16T23:52:00Z","message":"[Response Ops] Fix maintenance window custom schedule create and update error (#192649)\n\n## Summary\r\nFixes a bug where the backend would throw an error if we tried to create\r\nor update a maintenance window with a custom schedule. This was due to\r\nthe `form-lib` converting everything `frequency`, `interval`, and\r\n`customFrequency` field to a string and our logic assumed it was a\r\nnumber so the `===` comparisons were failing.\r\n\r\n### How to test:\r\n1. Navigate to the create maintenance window form\r\n2. Attempt to create a maintenance window with a custom schedule\r\n3. Assert the maintenance window was created successfully\r\n4. Attempt to edit the maintenance window with a different custom\r\nschedule\r\n5. Assert the maintenance window was edited successfully \r\n\r\nFixes: https://github.com/elastic/kibana/issues/192601\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"134b81572c4234e9c813aa5ed5dda286a99ffc32","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","backport:skip","Team:ResponseOps","v9.0.0","v8.16.0"],"title":"[Response Ops] Fix maintenance window custom schedule create and update error","number":192649,"url":"https://github.com/elastic/kibana/pull/192649","mergeCommit":{"message":"[Response Ops] Fix maintenance window custom schedule create and update error (#192649)\n\n## Summary\r\nFixes a bug where the backend would throw an error if we tried to create\r\nor update a maintenance window with a custom schedule. This was due to\r\nthe `form-lib` converting everything `frequency`, `interval`, and\r\n`customFrequency` field to a string and our logic assumed it was a\r\nnumber so the `===` comparisons were failing.\r\n\r\n### How to test:\r\n1. Navigate to the create maintenance window form\r\n2. Attempt to create a maintenance window with a custom schedule\r\n3. Assert the maintenance window was created successfully\r\n4. Attempt to edit the maintenance window with a different custom\r\nschedule\r\n5. Assert the maintenance window was edited successfully \r\n\r\nFixes: https://github.com/elastic/kibana/issues/192601\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"134b81572c4234e9c813aa5ed5dda286a99ffc32"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/192649","number":192649,"mergeCommit":{"message":"[Response Ops] Fix maintenance window custom schedule create and update error (#192649)\n\n## Summary\r\nFixes a bug where the backend would throw an error if we tried to create\r\nor update a maintenance window with a custom schedule. This was due to\r\nthe `form-lib` converting everything `frequency`, `interval`, and\r\n`customFrequency` field to a string and our logic assumed it was a\r\nnumber so the `===` comparisons were failing.\r\n\r\n### How to test:\r\n1. Navigate to the create maintenance window form\r\n2. Attempt to create a maintenance window with a custom schedule\r\n3. Assert the maintenance window was created successfully\r\n4. Attempt to edit the maintenance window with a different custom\r\nschedule\r\n5. Assert the maintenance window was edited successfully \r\n\r\nFixes: https://github.com/elastic/kibana/issues/192601\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"134b81572c4234e9c813aa5ed5dda286a99ffc32"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"url":"https://github.com/elastic/kibana/pull/208334","number":208334,"branch":"8.16","state":"OPEN"}]}] BACKPORT--> Co-authored-by: Jiawei Wu <74562234+JiaweiWu@users.noreply.github.com>
This commit is contained in:
parent
52fddd8394
commit
d7fac03932
18 changed files with 437 additions and 145 deletions
|
@ -22,16 +22,22 @@ export const rRuleRequestSchema = schema.object({
|
|||
interval: schema.maybe(
|
||||
schema.number({
|
||||
validate: (interval: number) => {
|
||||
if (interval < 1) return 'rRule interval must be > 0';
|
||||
if (!Number.isInteger(interval)) {
|
||||
return 'rRule interval must be an integer greater than 0';
|
||||
}
|
||||
},
|
||||
min: 1,
|
||||
})
|
||||
),
|
||||
until: schema.maybe(schema.string({ validate: validateEndDateV1 })),
|
||||
count: schema.maybe(
|
||||
schema.number({
|
||||
validate: (count: number) => {
|
||||
if (count < 1) return 'rRule count must be > 0';
|
||||
if (!Number.isInteger(count)) {
|
||||
return 'rRule count must be an integer greater than 0';
|
||||
}
|
||||
},
|
||||
min: 1,
|
||||
})
|
||||
),
|
||||
byweekday: schema.maybe(
|
||||
|
|
|
@ -96,12 +96,16 @@ describe('CreateMaintenanceWindowForm', () => {
|
|||
it('should initialize the form when no initialValue provided', () => {
|
||||
const result = appMockRenderer.render(<CreateMaintenanceWindowForm {...formProps} />);
|
||||
|
||||
const titleInput = within(result.getByTestId('title-field')).getByTestId('input');
|
||||
const titleInput = within(result.getByTestId('title-field')).getByTestId(
|
||||
'createMaintenanceWindowFormNameInput'
|
||||
);
|
||||
const dateInputs = within(result.getByTestId('date-field')).getAllByLabelText(
|
||||
// using the aria-label to query for the date-picker input
|
||||
'Press the down key to open a popover containing a calendar.'
|
||||
);
|
||||
const recurringInput = within(result.getByTestId('recurring-field')).getByTestId('input');
|
||||
const recurringInput = within(result.getByTestId('recurring-field')).getByTestId(
|
||||
'createMaintenanceWindowRepeatSwitch'
|
||||
);
|
||||
|
||||
expect(titleInput).toHaveValue('');
|
||||
// except for the date field
|
||||
|
@ -125,12 +129,16 @@ describe('CreateMaintenanceWindowForm', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
const titleInput = within(result.getByTestId('title-field')).getByTestId('input');
|
||||
const titleInput = within(result.getByTestId('title-field')).getByTestId(
|
||||
'createMaintenanceWindowFormNameInput'
|
||||
);
|
||||
const dateInputs = within(result.getByTestId('date-field')).getAllByLabelText(
|
||||
// using the aria-label to query for the date-picker input
|
||||
'Press the down key to open a popover containing a calendar.'
|
||||
);
|
||||
const recurringInput = within(result.getByTestId('recurring-field')).getByTestId('input');
|
||||
const recurringInput = within(result.getByTestId('recurring-field')).getByTestId(
|
||||
'createMaintenanceWindowRepeatSwitch'
|
||||
);
|
||||
const timezoneInput = within(result.getByTestId('timezone-field')).getByTestId(
|
||||
'comboBoxSearchInput'
|
||||
);
|
||||
|
|
|
@ -344,7 +344,7 @@ export const CreateMaintenanceWindowForm = React.memo<CreateMaintenanceWindowFor
|
|||
}, [categoryIds, isScopedQueryEnabled]);
|
||||
|
||||
return (
|
||||
<Form form={form}>
|
||||
<Form form={form} data-test-subj="createMaintenanceWindowForm">
|
||||
<EuiFlexGroup direction="column" responsive={false}>
|
||||
<EuiFlexItem>
|
||||
<UseField
|
||||
|
@ -352,6 +352,7 @@ export const CreateMaintenanceWindowForm = React.memo<CreateMaintenanceWindowFor
|
|||
componentProps={{
|
||||
'data-test-subj': 'title-field',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'createMaintenanceWindowFormNameInput',
|
||||
autoFocus: true,
|
||||
},
|
||||
}}
|
||||
|
@ -434,6 +435,9 @@ export const CreateMaintenanceWindowForm = React.memo<CreateMaintenanceWindowFor
|
|||
path="recurring"
|
||||
componentProps={{
|
||||
'data-test-subj': 'recurring-field',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'createMaintenanceWindowRepeatSwitch',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -24,7 +24,12 @@ export const EmptyPrompt = React.memo<EmptyPromptProps>(
|
|||
const renderActions = useMemo(() => {
|
||||
if (showCreateButton) {
|
||||
return [
|
||||
<EuiButton key="create-action" fill onClick={onClickCreate}>
|
||||
<EuiButton
|
||||
data-test-subj="mw-create-button"
|
||||
key="create-action"
|
||||
fill
|
||||
onClick={onClickCreate}
|
||||
>
|
||||
{i18n.EMPTY_PROMPT_BUTTON}
|
||||
</EuiButton>,
|
||||
<EuiButtonEmpty
|
||||
|
|
|
@ -67,9 +67,14 @@ describe('CustomRecurringSchedule', () => {
|
|||
</MockHookWrapperComponent>
|
||||
);
|
||||
|
||||
fireEvent.change(within(result.getByTestId('custom-frequency-field')).getByTestId('select'), {
|
||||
target: { value: Frequency.WEEKLY },
|
||||
});
|
||||
fireEvent.change(
|
||||
within(result.getByTestId('custom-frequency-field')).getByTestId(
|
||||
'customRecurringScheduleFrequencySelect'
|
||||
),
|
||||
{
|
||||
target: { value: Frequency.WEEKLY },
|
||||
}
|
||||
);
|
||||
await waitFor(() => expect(result.getByTestId('byweekday-field')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
|
@ -97,9 +102,14 @@ describe('CustomRecurringSchedule', () => {
|
|||
</MockHookWrapperComponent>
|
||||
);
|
||||
|
||||
fireEvent.change(within(result.getByTestId('custom-frequency-field')).getByTestId('select'), {
|
||||
target: { value: Frequency.MONTHLY },
|
||||
});
|
||||
fireEvent.change(
|
||||
within(result.getByTestId('custom-frequency-field')).getByTestId(
|
||||
'customRecurringScheduleFrequencySelect'
|
||||
),
|
||||
{
|
||||
target: { value: Frequency.MONTHLY },
|
||||
}
|
||||
);
|
||||
await waitFor(() => expect(result.getByTestId('bymonth-field')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
|
@ -111,9 +121,11 @@ describe('CustomRecurringSchedule', () => {
|
|||
);
|
||||
|
||||
const frequencyInput = within(result.getByTestId('custom-frequency-field')).getByTestId(
|
||||
'select'
|
||||
'customRecurringScheduleFrequencySelect'
|
||||
);
|
||||
const intervalInput = within(result.getByTestId('interval-field')).getByTestId(
|
||||
'customRecurringScheduleIntervalInput'
|
||||
);
|
||||
const intervalInput = within(result.getByTestId('interval-field')).getByTestId('input');
|
||||
|
||||
expect(frequencyInput).toHaveValue('2');
|
||||
expect(intervalInput).toHaveValue(1);
|
||||
|
@ -137,14 +149,16 @@ describe('CustomRecurringSchedule', () => {
|
|||
);
|
||||
|
||||
const frequencyInput = within(result.getByTestId('custom-frequency-field')).getByTestId(
|
||||
'select'
|
||||
'customRecurringScheduleFrequencySelect'
|
||||
);
|
||||
const intervalInput = within(result.getByTestId('interval-field')).getByTestId(
|
||||
'customRecurringScheduleIntervalInput'
|
||||
);
|
||||
const intervalInput = within(result.getByTestId('interval-field')).getByTestId('input');
|
||||
const input3 = within(result.getByTestId('byweekday-field'))
|
||||
.getByTestId('3')
|
||||
.getByTestId('isoWeekdays3')
|
||||
.getAttribute('aria-pressed');
|
||||
const input4 = within(result.getByTestId('byweekday-field'))
|
||||
.getByTestId('4')
|
||||
.getByTestId('isoWeekdays4')
|
||||
.getAttribute('aria-pressed');
|
||||
expect(frequencyInput).toHaveValue('2');
|
||||
expect(intervalInput).toHaveValue(3);
|
||||
|
|
|
@ -23,6 +23,7 @@ import * as i18n from '../../translations';
|
|||
import { getInitialByWeekday } from '../../helpers/get_initial_by_weekday';
|
||||
import { getWeekdayInfo } from '../../helpers/get_weekday_info';
|
||||
import { FormProps } from '../schema';
|
||||
import { parseSchedule } from '../../helpers/parse_schedule';
|
||||
|
||||
const UseField = getUseField({ component: Field });
|
||||
|
||||
|
@ -44,9 +45,13 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
],
|
||||
});
|
||||
|
||||
const parsedSchedule = useMemo(() => {
|
||||
return parseSchedule(recurringSchedule);
|
||||
}, [recurringSchedule]);
|
||||
|
||||
const frequencyOptions = useMemo(
|
||||
() => CREATE_FORM_CUSTOM_FREQUENCY(recurringSchedule?.interval),
|
||||
[recurringSchedule?.interval]
|
||||
() => CREATE_FORM_CUSTOM_FREQUENCY(parsedSchedule?.interval),
|
||||
[parsedSchedule?.interval]
|
||||
);
|
||||
|
||||
const bymonthOptions = useMemo(() => {
|
||||
|
@ -69,7 +74,7 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
|
||||
return (
|
||||
<>
|
||||
{recurringSchedule?.frequency !== Frequency.DAILY ? (
|
||||
{parsedSchedule?.frequency !== Frequency.DAILY ? (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup gutterSize="s" alignItems="flexStart">
|
||||
|
@ -81,6 +86,7 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
'data-test-subj': 'interval-field',
|
||||
id: 'interval',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'customRecurringScheduleIntervalInput',
|
||||
min: 1,
|
||||
prepend: (
|
||||
<EuiFormLabel htmlFor={'interval'}>
|
||||
|
@ -97,6 +103,7 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
componentProps={{
|
||||
'data-test-subj': 'custom-frequency-field',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'customRecurringScheduleFrequencySelect',
|
||||
options: frequencyOptions,
|
||||
},
|
||||
}}
|
||||
|
@ -106,8 +113,8 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
<EuiSpacer size="s" />
|
||||
</>
|
||||
) : null}
|
||||
{Number(recurringSchedule?.customFrequency) === Frequency.WEEKLY ||
|
||||
recurringSchedule?.frequency === Frequency.DAILY ? (
|
||||
{Number(parsedSchedule?.customFrequency) === Frequency.WEEKLY ||
|
||||
parsedSchedule?.frequency === Frequency.DAILY ? (
|
||||
<UseField
|
||||
path="recurringSchedule.byweekday"
|
||||
config={{
|
||||
|
@ -131,6 +138,7 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
componentProps={{
|
||||
'data-test-subj': 'byweekday-field',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'customRecurringScheduleByWeekdayButtonGroup',
|
||||
legend: 'Repeat on weekday',
|
||||
options: WEEKDAY_OPTIONS,
|
||||
},
|
||||
|
@ -138,7 +146,7 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
{Number(recurringSchedule?.customFrequency) === Frequency.MONTHLY ? (
|
||||
{Number(parsedSchedule?.customFrequency) === Frequency.MONTHLY ? (
|
||||
<UseField
|
||||
path="recurringSchedule.bymonth"
|
||||
componentProps={{
|
||||
|
|
|
@ -64,7 +64,7 @@ describe('RecurringSchedule', () => {
|
|||
</MockHookWrapperComponent>
|
||||
);
|
||||
|
||||
const btn = within(result.getByTestId('ends-field')).getByTestId('ondate');
|
||||
const btn = within(result.getByTestId('ends-field')).getByTestId('recurrenceEndOptionOnDate');
|
||||
|
||||
fireEvent.click(btn);
|
||||
expect(result.getByTestId('until-field')).toBeInTheDocument();
|
||||
|
@ -77,7 +77,7 @@ describe('RecurringSchedule', () => {
|
|||
</MockHookWrapperComponent>
|
||||
);
|
||||
|
||||
const btn = within(result.getByTestId('ends-field')).getByTestId('afterx');
|
||||
const btn = within(result.getByTestId('ends-field')).getByTestId('recurrenceEndOptionAfterX');
|
||||
|
||||
fireEvent.click(btn);
|
||||
expect(result.getByTestId('count-field')).toBeInTheDocument();
|
||||
|
@ -90,8 +90,12 @@ describe('RecurringSchedule', () => {
|
|||
</MockHookWrapperComponent>
|
||||
);
|
||||
|
||||
const frequencyInput = within(result.getByTestId('frequency-field')).getByTestId('select');
|
||||
const endsInput = within(result.getByTestId('ends-field')).getByTestId('never');
|
||||
const frequencyInput = within(result.getByTestId('frequency-field')).getByTestId(
|
||||
'recurringScheduleRepeatSelect'
|
||||
);
|
||||
const endsInput = within(result.getByTestId('ends-field')).getByTestId(
|
||||
'recurrenceEndOptionNever'
|
||||
);
|
||||
|
||||
expect(frequencyInput).toHaveValue('3');
|
||||
expect(endsInput).toHaveAttribute('aria-pressed', 'true');
|
||||
|
@ -112,8 +116,12 @@ describe('RecurringSchedule', () => {
|
|||
</MockHookWrapperComponent>
|
||||
);
|
||||
|
||||
const frequencyInput = within(result.getByTestId('frequency-field')).getByTestId('select');
|
||||
const endsInput = within(result.getByTestId('ends-field')).getByTestId('ondate');
|
||||
const frequencyInput = within(result.getByTestId('frequency-field')).getByTestId(
|
||||
'recurringScheduleRepeatSelect'
|
||||
);
|
||||
const endsInput = within(result.getByTestId('ends-field')).getByTestId(
|
||||
'recurrenceEndOptionOnDate'
|
||||
);
|
||||
const untilInput = within(result.getByTestId('until-field')).getByLabelText(
|
||||
// using the aria-label to query for the date-picker input
|
||||
'Press the down key to open a popover containing a calendar.'
|
||||
|
|
|
@ -34,6 +34,7 @@ import { CustomRecurringSchedule } from './custom_recurring_schedule';
|
|||
import { recurringSummary } from '../../helpers/recurring_summary';
|
||||
import { getPresets } from '../../helpers/get_presets';
|
||||
import { FormProps } from '../schema';
|
||||
import { parseSchedule } from '../../helpers/parse_schedule';
|
||||
|
||||
const UseField = getUseField({ component: Field });
|
||||
|
||||
|
@ -70,30 +71,39 @@ export const RecurringSchedule: React.FC = React.memo(() => {
|
|||
{
|
||||
text: i18n.CREATE_FORM_FREQUENCY_DAILY,
|
||||
value: Frequency.DAILY,
|
||||
'data-test-subj': 'recurringScheduleOptionDaily',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_FREQUENCY_WEEKLY_ON(dayOfWeek),
|
||||
value: Frequency.WEEKLY,
|
||||
'data-test-subj': 'recurringScheduleOptionWeekly',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_FREQUENCY_NTH_WEEKDAY(dayOfWeek)[
|
||||
isLastOfMonth ? 0 : nthWeekdayOfMonth
|
||||
],
|
||||
value: Frequency.MONTHLY,
|
||||
'data-test-subj': 'recurringScheduleOptionMonthly',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_FREQUENCY_YEARLY_ON(date),
|
||||
value: Frequency.YEARLY,
|
||||
'data-test-subj': 'recurringScheduleOptionYearly',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_FREQUENCY_CUSTOM,
|
||||
value: 'CUSTOM',
|
||||
'data-test-subj': 'recurringScheduleOptionCustom',
|
||||
},
|
||||
],
|
||||
presets: getPresets(date),
|
||||
};
|
||||
}, [startDate]);
|
||||
|
||||
const parsedSchedule = useMemo(() => {
|
||||
return parseSchedule(recurringSchedule);
|
||||
}, [recurringSchedule]);
|
||||
|
||||
return (
|
||||
<EuiSplitPanel.Outer hasShadow={false} hasBorder={true}>
|
||||
<EuiSplitPanel.Inner color="subdued">
|
||||
|
@ -102,14 +112,15 @@ export const RecurringSchedule: React.FC = React.memo(() => {
|
|||
componentProps={{
|
||||
'data-test-subj': 'frequency-field',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'recurringScheduleRepeatSelect',
|
||||
options,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{recurringSchedule?.frequency === Frequency.DAILY ||
|
||||
recurringSchedule?.frequency === 'CUSTOM' ? (
|
||||
{(parsedSchedule?.frequency === Frequency.DAILY ||
|
||||
parsedSchedule?.frequency === 'CUSTOM') && (
|
||||
<CustomRecurringSchedule data-test-subj="custom-recurring-form" />
|
||||
) : null}
|
||||
)}
|
||||
<UseField
|
||||
path="recurringSchedule.ends"
|
||||
componentProps={{
|
||||
|
@ -120,7 +131,7 @@ export const RecurringSchedule: React.FC = React.memo(() => {
|
|||
},
|
||||
}}
|
||||
/>
|
||||
{recurringSchedule?.ends === EndsOptions.ON_DATE ? (
|
||||
{parsedSchedule?.ends === EndsOptions.ON_DATE ? (
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup alignItems="flexEnd">
|
||||
|
@ -164,13 +175,14 @@ export const RecurringSchedule: React.FC = React.memo(() => {
|
|||
</EuiFlexGroup>
|
||||
</>
|
||||
) : null}
|
||||
{recurringSchedule?.ends === EndsOptions.AFTER_X ? (
|
||||
{parsedSchedule?.ends === EndsOptions.AFTER_X ? (
|
||||
<UseField
|
||||
path="recurringSchedule.count"
|
||||
componentProps={{
|
||||
'data-test-subj': 'count-field',
|
||||
id: 'count',
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'recurringScheduleAfterXOccurenceInput',
|
||||
type: 'number',
|
||||
min: 1,
|
||||
prepend: (
|
||||
|
@ -187,7 +199,7 @@ export const RecurringSchedule: React.FC = React.memo(() => {
|
|||
<EuiHorizontalRule margin="none" />
|
||||
<EuiSplitPanel.Inner>
|
||||
{i18n.CREATE_FORM_RECURRING_SUMMARY_PREFIX(
|
||||
recurringSummary(moment(startDate), recurringSchedule, presets)
|
||||
recurringSummary(moment(startDate), parsedSchedule, presets)
|
||||
)}
|
||||
</EuiSplitPanel.Inner>
|
||||
</EuiSplitPanel.Outer>
|
||||
|
|
|
@ -60,33 +60,50 @@ export enum EndsOptions {
|
|||
}
|
||||
|
||||
export const RECURRENCE_END_OPTIONS = [
|
||||
{ id: 'never', label: i18n.CREATE_FORM_ENDS_NEVER },
|
||||
{ id: 'ondate', label: i18n.CREATE_FORM_ENDS_ON_DATE },
|
||||
{ id: 'afterx', label: i18n.CREATE_FORM_ENDS_AFTER_X },
|
||||
{
|
||||
id: 'never',
|
||||
label: i18n.CREATE_FORM_ENDS_NEVER,
|
||||
'data-test-subj': 'recurrenceEndOptionNever',
|
||||
},
|
||||
{
|
||||
id: 'ondate',
|
||||
label: i18n.CREATE_FORM_ENDS_ON_DATE,
|
||||
'data-test-subj': 'recurrenceEndOptionOnDate',
|
||||
},
|
||||
{
|
||||
id: 'afterx',
|
||||
label: i18n.CREATE_FORM_ENDS_AFTER_X,
|
||||
'data-test-subj': 'recurrenceEndOptionAfterX',
|
||||
},
|
||||
];
|
||||
|
||||
export const CREATE_FORM_CUSTOM_FREQUENCY = (interval: number = 1) => [
|
||||
{
|
||||
text: i18n.CREATE_FORM_CUSTOM_FREQUENCY_DAILY(interval),
|
||||
value: Frequency.DAILY,
|
||||
'data-test-subj': 'customFrequencyDaily',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_CUSTOM_FREQUENCY_WEEKLY(interval),
|
||||
value: Frequency.WEEKLY,
|
||||
'data-test-subj': 'customFrequencyWeekly',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_CUSTOM_FREQUENCY_MONTHLY(interval),
|
||||
value: Frequency.MONTHLY,
|
||||
'data-test-subj': 'customFrequencyMonthly',
|
||||
},
|
||||
{
|
||||
text: i18n.CREATE_FORM_CUSTOM_FREQUENCY_YEARLY(interval),
|
||||
value: Frequency.YEARLY,
|
||||
'data-test-subj': 'customFrequencyYearly',
|
||||
},
|
||||
];
|
||||
|
||||
export const WEEKDAY_OPTIONS = ISO_WEEKDAYS.map((n) => ({
|
||||
id: String(n),
|
||||
label: moment().isoWeekday(n).format('ddd'),
|
||||
'data-test-subj': `isoWeekdays${n}`,
|
||||
}));
|
||||
|
||||
export const ISO_WEEKDAYS_TO_RRULE: Record<number, string> = {
|
||||
|
|
|
@ -12,20 +12,23 @@ import { getNthByWeekday } from './get_nth_by_weekday';
|
|||
import { RecurringScheduleFormProps } from '../components/schema';
|
||||
import { getPresets } from './get_presets';
|
||||
import { RRuleParams } from '../../../../common';
|
||||
import { parseSchedule } from './parse_schedule';
|
||||
|
||||
export const convertToRRule = (
|
||||
startDate: Moment,
|
||||
timezone: string,
|
||||
recurringForm?: RecurringScheduleFormProps
|
||||
recurringSchedule?: RecurringScheduleFormProps
|
||||
): RRuleParams => {
|
||||
const presets = getPresets(startDate);
|
||||
|
||||
const parsedSchedule = parseSchedule(recurringSchedule);
|
||||
|
||||
const rRule: RRuleParams = {
|
||||
dtstart: startDate.toISOString(),
|
||||
tzid: timezone,
|
||||
};
|
||||
|
||||
if (!recurringForm)
|
||||
if (!parsedSchedule)
|
||||
return {
|
||||
...rRule,
|
||||
// default to yearly and a count of 1
|
||||
|
@ -34,9 +37,9 @@ export const convertToRRule = (
|
|||
count: 1,
|
||||
};
|
||||
|
||||
let form = recurringForm;
|
||||
if (recurringForm.frequency !== 'CUSTOM') {
|
||||
form = { ...recurringForm, ...presets[recurringForm.frequency] };
|
||||
let form = parsedSchedule;
|
||||
if (parsedSchedule.frequency !== 'CUSTOM') {
|
||||
form = { ...parsedSchedule, ...presets[parsedSchedule.frequency] };
|
||||
}
|
||||
|
||||
const frequency = form.customFrequency ?? (form.frequency as Frequency);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { RecurringScheduleFormProps } from '../components/schema';
|
||||
|
||||
export const parseSchedule = (
|
||||
schedule: RecurringScheduleFormProps | undefined
|
||||
): RecurringScheduleFormProps | undefined => {
|
||||
if (!schedule) {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
const { frequency, customFrequency, interval, count } = schedule;
|
||||
|
||||
// We must case them to unknown because form-lib is already turning them into strings
|
||||
// despite what our types suggests
|
||||
const parsedFrequency = parseInt(frequency as string, 10);
|
||||
const parsedCustomFrequency = parseInt(customFrequency as unknown as string, 10);
|
||||
const parsedInterval = parseInt(interval as unknown as string, 10);
|
||||
const parsedCount = parseInt(count as unknown as string, 10);
|
||||
|
||||
const shallowCopy = { ...schedule };
|
||||
|
||||
if (!isNaN(parsedFrequency)) {
|
||||
shallowCopy.frequency = parsedFrequency;
|
||||
}
|
||||
|
||||
if (!isNaN(parsedCustomFrequency)) {
|
||||
shallowCopy.customFrequency = parsedCustomFrequency;
|
||||
}
|
||||
|
||||
if (!isNaN(parsedInterval)) {
|
||||
shallowCopy.interval = parsedInterval;
|
||||
}
|
||||
|
||||
if (!isNaN(parsedCount)) {
|
||||
shallowCopy.count = parsedCount;
|
||||
}
|
||||
|
||||
return shallowCopy;
|
||||
};
|
|
@ -24,80 +24,76 @@ export const recurringSummary = (
|
|||
) => {
|
||||
if (!recurringSchedule) return '';
|
||||
|
||||
if (recurringSchedule) {
|
||||
let schedule = recurringSchedule;
|
||||
if (recurringSchedule.frequency !== 'CUSTOM') {
|
||||
schedule = { ...recurringSchedule, ...presets[recurringSchedule.frequency] };
|
||||
}
|
||||
|
||||
const frequency =
|
||||
schedule.customFrequency ?? (schedule.frequency as MaintenanceWindowFrequency);
|
||||
const interval = schedule.interval || 1;
|
||||
const frequencySummary = i18n.CREATE_FORM_FREQUENCY_SUMMARY(interval)[frequency];
|
||||
|
||||
// daily and weekly
|
||||
let weeklySummary = null;
|
||||
let dailyWeekdaySummary = null;
|
||||
let dailyWithWeekdays = false;
|
||||
const byweekday = schedule.byweekday;
|
||||
if (byweekday) {
|
||||
const weekdays = Object.keys(byweekday)
|
||||
.filter((k) => byweekday[k] === true)
|
||||
.map((n) => ISO_WEEKDAYS_TO_RRULE[Number(n)]);
|
||||
const formattedWeekdays = weekdays.map((weekday) => toWeekdayName(weekday)).join(', ');
|
||||
|
||||
weeklySummary = i18n.CREATE_FORM_WEEKLY_SUMMARY(formattedWeekdays);
|
||||
dailyWeekdaySummary = formattedWeekdays;
|
||||
|
||||
dailyWithWeekdays = frequency === Frequency.DAILY;
|
||||
}
|
||||
|
||||
// monthly
|
||||
let monthlySummary = null;
|
||||
const bymonth = schedule.bymonth;
|
||||
if (bymonth) {
|
||||
if (bymonth === 'weekday') {
|
||||
const nthWeekday = getNthByWeekday(startDate);
|
||||
const nth = nthWeekday.startsWith('-1') ? 0 : Number(nthWeekday[1]);
|
||||
monthlySummary = i18n.CREATE_FORM_WEEKDAY_SHORT(toWeekdayName(nthWeekday))[nth];
|
||||
monthlySummary = monthlySummary[0].toLocaleLowerCase() + monthlySummary.slice(1);
|
||||
} else if (bymonth === 'day') {
|
||||
monthlySummary = i18n.CREATE_FORM_MONTHLY_BY_DAY_SUMMARY(startDate.date());
|
||||
}
|
||||
}
|
||||
|
||||
// yearly
|
||||
const yearlyByMonthSummary = i18n.CREATE_FORM_YEARLY_BY_MONTH_SUMMARY(
|
||||
monthDayDate(moment().month(startDate.month()).date(startDate.date()))
|
||||
);
|
||||
|
||||
const onSummary = dailyWithWeekdays
|
||||
? dailyWeekdaySummary
|
||||
: frequency === Frequency.WEEKLY
|
||||
? weeklySummary
|
||||
: frequency === Frequency.MONTHLY
|
||||
? monthlySummary
|
||||
: frequency === Frequency.YEARLY
|
||||
? yearlyByMonthSummary
|
||||
: null;
|
||||
|
||||
const untilSummary = schedule.until
|
||||
? i18n.CREATE_FORM_UNTIL_DATE_SUMMARY(moment(schedule.until).format('LL'))
|
||||
: schedule.count
|
||||
? i18n.CREATE_FORM_OCURRENCES_SUMMARY(schedule.count)
|
||||
: null;
|
||||
|
||||
const every = i18n
|
||||
.CREATE_FORM_RECURRING_SUMMARY(
|
||||
!dailyWithWeekdays ? frequencySummary : null,
|
||||
onSummary,
|
||||
untilSummary
|
||||
)
|
||||
.trim();
|
||||
|
||||
return every;
|
||||
let schedule = recurringSchedule;
|
||||
if (recurringSchedule.frequency !== 'CUSTOM') {
|
||||
schedule = { ...recurringSchedule, ...presets[recurringSchedule.frequency] };
|
||||
}
|
||||
return '';
|
||||
|
||||
const frequency = schedule.customFrequency ?? (schedule.frequency as MaintenanceWindowFrequency);
|
||||
const interval = schedule.interval || 1;
|
||||
const frequencySummary = i18n.CREATE_FORM_FREQUENCY_SUMMARY(interval)[frequency];
|
||||
|
||||
// daily and weekly
|
||||
let weeklySummary = null;
|
||||
let dailyWeekdaySummary = null;
|
||||
let dailyWithWeekdays = false;
|
||||
const byweekday = schedule.byweekday;
|
||||
if (byweekday) {
|
||||
const weekdays = Object.keys(byweekday)
|
||||
.filter((k) => byweekday[k] === true)
|
||||
.map((n) => ISO_WEEKDAYS_TO_RRULE[Number(n)]);
|
||||
const formattedWeekdays = weekdays.map((weekday) => toWeekdayName(weekday)).join(', ');
|
||||
|
||||
weeklySummary = i18n.CREATE_FORM_WEEKLY_SUMMARY(formattedWeekdays);
|
||||
dailyWeekdaySummary = formattedWeekdays;
|
||||
|
||||
dailyWithWeekdays = frequency === Frequency.DAILY;
|
||||
}
|
||||
|
||||
// monthly
|
||||
let monthlySummary = null;
|
||||
const bymonth = schedule.bymonth;
|
||||
if (bymonth) {
|
||||
if (bymonth === 'weekday') {
|
||||
const nthWeekday = getNthByWeekday(startDate);
|
||||
const nth = nthWeekday.startsWith('-1') ? 0 : Number(nthWeekday[1]);
|
||||
monthlySummary = i18n.CREATE_FORM_WEEKDAY_SHORT(toWeekdayName(nthWeekday))[nth];
|
||||
monthlySummary = monthlySummary[0].toLocaleLowerCase() + monthlySummary.slice(1);
|
||||
} else if (bymonth === 'day') {
|
||||
monthlySummary = i18n.CREATE_FORM_MONTHLY_BY_DAY_SUMMARY(startDate.date());
|
||||
}
|
||||
}
|
||||
|
||||
// yearly
|
||||
const yearlyByMonthSummary = i18n.CREATE_FORM_YEARLY_BY_MONTH_SUMMARY(
|
||||
monthDayDate(moment().month(startDate.month()).date(startDate.date()))
|
||||
);
|
||||
|
||||
const onSummary = dailyWithWeekdays
|
||||
? dailyWeekdaySummary
|
||||
: frequency === Frequency.WEEKLY
|
||||
? weeklySummary
|
||||
: frequency === Frequency.MONTHLY
|
||||
? monthlySummary
|
||||
: frequency === Frequency.YEARLY
|
||||
? yearlyByMonthSummary
|
||||
: null;
|
||||
|
||||
const untilSummary = schedule.until
|
||||
? i18n.CREATE_FORM_UNTIL_DATE_SUMMARY(moment(schedule.until).format('LL'))
|
||||
: schedule.count
|
||||
? i18n.CREATE_FORM_OCURRENCES_SUMMARY(schedule.count)
|
||||
: null;
|
||||
|
||||
const every = i18n
|
||||
.CREATE_FORM_RECURRING_SUMMARY(
|
||||
!dailyWithWeekdays ? frequencySummary : null,
|
||||
onSummary,
|
||||
untilSummary
|
||||
)
|
||||
.trim();
|
||||
|
||||
return every;
|
||||
};
|
||||
|
||||
export const toWeekdayName = (weekday: string) =>
|
||||
|
|
|
@ -13,25 +13,27 @@ export const rRuleSchema = schema.object({
|
|||
dtstart: schema.string({ validate: validateSnoozeStartDate }),
|
||||
tzid: schema.string(),
|
||||
freq: schema.maybe(
|
||||
schema.number({
|
||||
validate: (freq: number) => {
|
||||
if (freq < 0 || freq > 3) return 'rRule freq must be 0, 1, 2, or 3';
|
||||
},
|
||||
})
|
||||
schema.oneOf([schema.literal(0), schema.literal(1), schema.literal(2), schema.literal(3)])
|
||||
),
|
||||
interval: schema.maybe(
|
||||
schema.number({
|
||||
validate: (interval: number) => {
|
||||
if (interval < 1) return 'rRule interval must be > 0';
|
||||
if (!Number.isInteger(interval)) {
|
||||
return 'rRule interval must be an integer greater than 0';
|
||||
}
|
||||
},
|
||||
min: 1,
|
||||
})
|
||||
),
|
||||
until: schema.maybe(schema.string({ validate: validateSnoozeEndDate })),
|
||||
count: schema.maybe(
|
||||
schema.number({
|
||||
validate: (count: number) => {
|
||||
if (count < 1) return 'rRule count must be > 0';
|
||||
if (!Number.isInteger(count)) {
|
||||
return 'rRule count must be an integer greater than 0';
|
||||
}
|
||||
},
|
||||
min: 1,
|
||||
})
|
||||
),
|
||||
byweekday: schema.maybe(
|
||||
|
|
|
@ -10,5 +10,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
|
|||
export default ({ loadTestFile }: FtrProviderContext) => {
|
||||
describe('Maintenance Windows', function () {
|
||||
loadTestFile(require.resolve('./maintenance_windows_table'));
|
||||
loadTestFile(require.resolve('./maintenance_window_create_form'));
|
||||
loadTestFile(require.resolve('./maintenance_window_update_form'));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { ObjectRemover } from '../../../lib/object_remover';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const supertest = getService('supertest');
|
||||
const pageObjects = getPageObjects(['common', 'header']);
|
||||
const retry = getService('retry');
|
||||
const toasts = getService('toasts');
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
|
||||
describe('Maintenance window create form', () => {
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('maintenanceWindows');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
const { body } = await supertest.get('/internal/alerting/rules/maintenance_window/_find');
|
||||
|
||||
body?.data?.forEach((mw: { id: string }) => {
|
||||
objectRemover.add(mw.id, 'rules/maintenance_window', 'alerting', true);
|
||||
});
|
||||
|
||||
await objectRemover.removeAll();
|
||||
});
|
||||
|
||||
it('should create a maintenance window', async () => {
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
await testSubjects.click('mw-create-button');
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('createMaintenanceWindowForm');
|
||||
});
|
||||
|
||||
const nameInput = await testSubjects.find('createMaintenanceWindowFormNameInput');
|
||||
|
||||
await nameInput.click();
|
||||
await nameInput.type('Test Maintenance Window');
|
||||
|
||||
// Turn on repeat
|
||||
await (await testSubjects.find('createMaintenanceWindowRepeatSwitch')).click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('recurringScheduleRepeatSelect');
|
||||
});
|
||||
|
||||
// Open the repeat dropdown select
|
||||
await (await testSubjects.find('recurringScheduleRepeatSelect')).click();
|
||||
// Select custom
|
||||
await (await testSubjects.find('recurringScheduleOptionCustom')).click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('customRecurringScheduleFrequencySelect');
|
||||
});
|
||||
|
||||
// Change interval to 2
|
||||
const intervalInput = await testSubjects.find('customRecurringScheduleIntervalInput');
|
||||
|
||||
await intervalInput.click();
|
||||
await intervalInput.type('2');
|
||||
|
||||
// Open "every" frequency dropdown
|
||||
await (await testSubjects.find('customRecurringScheduleFrequencySelect')).click();
|
||||
// Select daily
|
||||
await (await testSubjects.find('customFrequencyDaily')).click();
|
||||
// Click on "End -> after {X}"
|
||||
await (await testSubjects.find('recurrenceEndOptionAfterX')).click();
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('count-field');
|
||||
});
|
||||
|
||||
const afterXOccurenceInput = await testSubjects.find('recurringScheduleAfterXOccurenceInput');
|
||||
|
||||
await afterXOccurenceInput.click();
|
||||
await afterXOccurenceInput.clearValue();
|
||||
await afterXOccurenceInput.type('5');
|
||||
|
||||
await (await testSubjects.find('create-submit')).click();
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await toasts.getTitleAndDismiss();
|
||||
expect(toastTitle).to.eql(`Created maintenance window 'Test Maintenance Window'`);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { ObjectRemover } from '../../../lib/object_remover';
|
||||
import { createMaintenanceWindow } from './utils';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const supertest = getService('supertest');
|
||||
const pageObjects = getPageObjects(['common', 'maintenanceWindows', 'header']);
|
||||
const retry = getService('retry');
|
||||
const toasts = getService('toasts');
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
const browser = getService('browser');
|
||||
|
||||
describe('Maintenance window update form', () => {
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('maintenanceWindows');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await objectRemover.removeAll();
|
||||
});
|
||||
|
||||
it('should update a maintenance window', async () => {
|
||||
const createdMaintenanceWindow = await createMaintenanceWindow({
|
||||
name: 'Test Maintenance Window',
|
||||
getService,
|
||||
overwrite: {
|
||||
r_rule: {
|
||||
dtstart: new Date().toISOString(),
|
||||
tzid: 'UTC',
|
||||
freq: 3,
|
||||
interval: 12,
|
||||
count: 5,
|
||||
},
|
||||
category_ids: ['management', 'observability', 'securitySolution'],
|
||||
},
|
||||
});
|
||||
|
||||
objectRemover.add(createdMaintenanceWindow.id, 'rules/maintenance_window', 'alerting', true);
|
||||
|
||||
await browser.refresh();
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows('Test Maintenance Window');
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-edit');
|
||||
|
||||
await retry.try(async () => {
|
||||
await testSubjects.existOrFail('createMaintenanceWindowForm');
|
||||
});
|
||||
|
||||
const nameInput = await testSubjects.find('createMaintenanceWindowFormNameInput');
|
||||
|
||||
await nameInput.click();
|
||||
await nameInput.clearValue();
|
||||
await nameInput.type('Test Maintenance Window updated');
|
||||
|
||||
// Open the repeat dropdown select
|
||||
await (await testSubjects.find('recurringScheduleRepeatSelect')).click();
|
||||
// Select daily
|
||||
await (await testSubjects.find('recurringScheduleOptionDaily')).click();
|
||||
|
||||
await (await testSubjects.find('create-submit')).click();
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await toasts.getTitleAndDismiss();
|
||||
expect(toastTitle).to.eql(`Updated maintenance window 'Test Maintenance Window updated'`);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -9,22 +9,18 @@ import expect from '@kbn/expect';
|
|||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
import { ObjectRemover } from '../../../lib/object_remover';
|
||||
import { generateUniqueKey } from '../../../lib/get_test_data';
|
||||
import { createMaintenanceWindow, createObjectRemover } from './utils';
|
||||
import { createMaintenanceWindow } from './utils';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const supertest = getService('supertest');
|
||||
const pageObjects = getPageObjects(['common', 'maintenanceWindows', 'header']);
|
||||
const retry = getService('retry');
|
||||
const toasts = getService('toasts');
|
||||
|
||||
let objectRemover: ObjectRemover;
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
const browser = getService('browser');
|
||||
|
||||
describe('Maintenance windows table', function () {
|
||||
before(async () => {
|
||||
objectRemover = await createObjectRemover({ getService });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('maintenanceWindows');
|
||||
});
|
||||
|
|
|
@ -5,30 +5,20 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ObjectRemover } from '../../../lib/object_remover';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export const createObjectRemover = async ({
|
||||
getService,
|
||||
}: {
|
||||
getService: FtrProviderContext['getService'];
|
||||
}) => {
|
||||
const supertest = getService('supertest');
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
|
||||
return objectRemover;
|
||||
};
|
||||
|
||||
export const createMaintenanceWindow = async ({
|
||||
name,
|
||||
startDate,
|
||||
notRecurring,
|
||||
getService,
|
||||
overwrite,
|
||||
}: {
|
||||
name: string;
|
||||
startDate?: Date;
|
||||
notRecurring?: boolean;
|
||||
getService: FtrProviderContext['getService'];
|
||||
overwrite?: Record<string, any>;
|
||||
}) => {
|
||||
const supertest = getService('supertest');
|
||||
const dtstart = startDate ? startDate : new Date();
|
||||
|
@ -40,6 +30,7 @@ export const createMaintenanceWindow = async ({
|
|||
tzid: 'UTC',
|
||||
...(notRecurring ? { freq: 1, count: 1 } : { freq: 2 }),
|
||||
},
|
||||
...overwrite,
|
||||
};
|
||||
|
||||
const { body } = await supertest
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue