diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.test.tsx index 5ff3d23da7ec6f..c3efb2d0d89aea 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.test.tsx @@ -6,18 +6,20 @@ */ import React from 'react'; +import moment from 'moment'; import { fireEvent, render, screen } from '@testing-library/react'; -import { ManualRuleRunModal } from '.'; +import { ManualRuleRunModal, MAX_SCHEDULE_BACKFILL_LOOKBACK_WINDOW_DAYS } from '.'; -const DATE_PICKER_PREVIOUS_BTN_CLASS = '.react-datepicker__navigation--previous'; -const DATE_PICKER_NEXT_BTN_CLASS = '.react-datepicker__navigation--next'; +const convertToDatePickerFormat = (date: moment.Moment) => { + return `${date.format('L')} ${date.format('LT')}`; +}; describe('ManualRuleRunModal', () => { const onCancelMock = jest.fn(); const onConfirmMock = jest.fn(); - let startDatePicker: HTMLElement; - let endDatePicker: HTMLElement; + let startDatePicker: Element; + let endDatePicker: Element; let confirmModalConfirmButton: HTMLElement; let cancelModalConfirmButton: HTMLElement; let timeRangeForm: HTMLElement; @@ -28,18 +30,13 @@ describe('ManualRuleRunModal', () => { }); beforeEach(() => { - // This is an attempt to fix the "TypeError: scrollIntoView is not a function" error - // According to https://stackoverflow.com/a/53294906 the `scrollIntoView` is not implemented in jsdom, - // and proposed solution is coming from https://github.com/jsdom/jsdom/issues/1695 - window.HTMLElement.prototype.scrollIntoView = () => {}; - render(); - startDatePicker = screen.getByTestId('start-date-picker'); - endDatePicker = screen.getByTestId('end-date-picker'); + timeRangeForm = screen.getByTestId('manual-rule-run-time-range-form'); + startDatePicker = timeRangeForm.getElementsByClassName('start-date-picker')[0]; + endDatePicker = timeRangeForm.getElementsByClassName('end-date-picker')[0]; confirmModalConfirmButton = screen.getByTestId('confirmModalConfirmButton'); cancelModalConfirmButton = screen.getByTestId('confirmModalCancelButton'); - timeRangeForm = screen.getByTestId('manual-rule-run-time-range-form'); }); it('should render modal', () => { @@ -51,7 +48,16 @@ describe('ManualRuleRunModal', () => { it('should render confirmation button disabled if invalid time range has been selected', () => { expect(confirmModalConfirmButton).toBeEnabled(); - fireEvent.click(endDatePicker.querySelector(DATE_PICKER_PREVIOUS_BTN_CLASS)!); + const now = moment(); + const startDate = now.clone().subtract(1, 'd'); + const endDate = now.clone().subtract(2, 'd'); + + fireEvent.change(startDatePicker, { + target: { value: convertToDatePickerFormat(startDate) }, + }); + fireEvent.change(endDatePicker, { + target: { value: convertToDatePickerFormat(endDate) }, + }); expect(confirmModalConfirmButton).toBeDisabled(); expect(timeRangeForm).toHaveTextContent('Selected time range is invalid'); @@ -60,10 +66,14 @@ describe('ManualRuleRunModal', () => { it('should render confirmation button disabled if selected start date is more than 90 days in the past', () => { expect(confirmModalConfirmButton).toBeEnabled(); - fireEvent.click(startDatePicker.querySelector(DATE_PICKER_PREVIOUS_BTN_CLASS)!); - fireEvent.click(startDatePicker.querySelector(DATE_PICKER_PREVIOUS_BTN_CLASS)!); - fireEvent.click(startDatePicker.querySelector(DATE_PICKER_PREVIOUS_BTN_CLASS)!); - fireEvent.click(startDatePicker.querySelector(DATE_PICKER_PREVIOUS_BTN_CLASS)!); + const now = moment(); + const startDate = now.clone().subtract(MAX_SCHEDULE_BACKFILL_LOOKBACK_WINDOW_DAYS, 'd'); + + fireEvent.change(startDatePicker, { + target: { + value: convertToDatePickerFormat(startDate), + }, + }); expect(confirmModalConfirmButton).toBeDisabled(); expect(timeRangeForm).toHaveTextContent( @@ -74,7 +84,12 @@ describe('ManualRuleRunModal', () => { it('should render confirmation button disabled if selected end date is in future', () => { expect(confirmModalConfirmButton).toBeEnabled(); - fireEvent.click(endDatePicker.querySelector(DATE_PICKER_NEXT_BTN_CLASS)!); + const now = moment(); + const endDate = now.clone().add(2, 'd'); + + fireEvent.change(endDatePicker, { + target: { value: convertToDatePickerFormat(endDate) }, + }); expect(confirmModalConfirmButton).toBeDisabled(); expect(timeRangeForm).toHaveTextContent('Manual rule run cannot be scheduled for the future'); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.tsx index 365ebc865ec321..00a3e4b262aa75 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/index.tsx @@ -13,8 +13,6 @@ import { EuiFlexItem, EuiForm, EuiFormRow, - EuiHorizontalRule, - EuiSpacer, useGeneratedHtmlId, } from '@elastic/eui'; import moment from 'moment'; @@ -23,6 +21,8 @@ import { TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_TOOLTIP } from '../../../../common import * as i18n from './translations'; +const MANUAL_RULE_RUN_MODAL_WIDTH = 600; + export const MAX_SCHEDULE_BACKFILL_LOOKBACK_WINDOW_DAYS = 90; interface ManualRuleRunModalProps { @@ -68,36 +68,34 @@ const ManualRuleRunModalComponent = ({ onCancel, onConfirm }: ManualRuleRunModal return ( + {i18n.MANUAL_RULE_RUN_MODAL_TITLE} + + + + + } + titleProps={{ id: modalTitleId, style: { width: '100%' } }} onCancel={onCancel} onConfirm={handleConfirm} confirmButtonText={i18n.MANUAL_RULE_RUN_CONFIRM_BUTTON} cancelButtonText={i18n.MANUAL_RULE_RUN_CANCEL_BUTTON} confirmButtonDisabled={isInvalid} + style={{ width: MANUAL_RULE_RUN_MODAL_WIDTH }} > - - + - {i18n.MANUAL_RULE_RUN_TIME_RANGE_TITLE} - - - - - } + label={i18n.MANUAL_RULE_RUN_TIME_RANGE_TITLE} isInvalid={isInvalid} error={errorMessage} > date && setStartDate(date)} @@ -108,6 +106,7 @@ const ManualRuleRunModalComponent = ({ onCancel, onConfirm }: ManualRuleRunModal } endDateControl={ date && setEndDate(date)} @@ -118,30 +117,6 @@ const ManualRuleRunModalComponent = ({ onCancel, onConfirm }: ManualRuleRunModal } /> - - - date && setStartDate(date)} - startDate={startDate} - endDate={endDate} - showTimeSelect={true} - /> - - - - date && setEndDate(date)} - startDate={startDate} - endDate={endDate} - showTimeSelect={true} - /> - ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/translations.ts index c640377ed3b23b..737a992b3a5a37 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/manual_rule_run/translations.ts @@ -6,57 +6,64 @@ */ import { i18n } from '@kbn/i18n'; +export const MANUAL_RULE_RUN_MODAL_TITLE = i18n.translate( + 'xpack.securitySolution.manualRuleRun.modalTitle', + { + defaultMessage: 'Manual rule run', + } +); + export const MANUAL_RULE_RUN_TIME_RANGE_TITLE = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.timeRangeTitle', + 'xpack.securitySolution.manualRuleRun.timeRangeTitle', { defaultMessage: 'Select timerange for manual rule run', } ); export const MANUAL_RULE_RUN_START_AT_TITLE = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.startAtTitle', + 'xpack.securitySolution.manualRuleRun.startAtTitle', { defaultMessage: 'Start at', } ); export const MANUAL_RULE_RUN_END_AT_TITLE = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.endAtTitle', + 'xpack.securitySolution.manualRuleRun.endAtTitle', { defaultMessage: 'Finish at', } ); export const MANUAL_RULE_RUN_CONFIRM_BUTTON = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.confirmButton', + 'xpack.securitySolution.manualRuleRun.confirmButton', { defaultMessage: 'Run', } ); export const MANUAL_RULE_RUN_CANCEL_BUTTON = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.cancelButton', + 'xpack.securitySolution.manualRuleRun.cancelButton', { defaultMessage: 'Cancel', } ); export const MANUAL_RULE_RUN_INVALID_TIME_RANGE_ERROR = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.invalidTimeRangeError', + 'xpack.securitySolution.manualRuleRun.invalidTimeRangeError', { defaultMessage: 'Selected time range is invalid', } ); export const MANUAL_RULE_RUN_FUTURE_TIME_RANGE_ERROR = i18n.translate( - 'xpack.securitySolution.manuelRuleRun.futureTimeRangeError', + 'xpack.securitySolution.manualRuleRun.futureTimeRangeError', { defaultMessage: 'Manual rule run cannot be scheduled for the future', } ); export const MANUAL_RULE_RUN_START_DATE_OUT_OF_RANGE_ERROR = (maxDaysLookback: number) => - i18n.translate('xpack.securitySolution.manuelRuleRun.startDateIsOutOfRangeError', { + i18n.translate('xpack.securitySolution.manuelRulaRun.startDateIsOutOfRangeError', { values: { maxDaysLookback }, defaultMessage: 'Manual rule run cannot be scheduled earlier than {maxDaysLookback, plural, =1 {# day} other {# days}} ago',