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',