diff --git a/src/platform/packages/shared/response-ops/recurring-schedule-form/components/recurring_schedule_form_fields.tsx b/src/platform/packages/shared/response-ops/recurring-schedule-form/components/recurring_schedule_form_fields.tsx index b51c337910d9b..85c70c454e138 100644 --- a/src/platform/packages/shared/response-ops/recurring-schedule-form/components/recurring_schedule_form_fields.tsx +++ b/src/platform/packages/shared/response-ops/recurring-schedule-form/components/recurring_schedule_form_fields.tsx @@ -41,13 +41,12 @@ import { getPresets } from '../utils/get_presets'; import { getWeekdayInfo } from '../utils/get_weekday_info'; import { RecurringSchedule } from '../types'; import * as i18n from '../translations'; +import { convertStringToMomentOptional, convertMomentToStringOptional } from '../converters/moment'; /** * Using EuiForm in `div` mode since this is meant to be integrated in a larger form */ const UseField = getUseField({ component: Field }); -export const toMoment = (value?: string): Moment | undefined => (value ? moment(value) : undefined); -export const toString = (value?: Moment): string => value?.toISOString() ?? ''; export interface RecurringScheduleFieldsProps { startDate?: string; @@ -211,8 +210,8 @@ export const RecurringScheduleFormFields = memo( }, }, ], - serializer: toString, - deserializer: toMoment, + serializer: convertMomentToStringOptional, + deserializer: convertStringToMomentOptional, }} componentProps={{ 'data-test-subj': 'until-field', diff --git a/src/platform/packages/shared/response-ops/recurring-schedule-form/converters/moment.test.ts b/src/platform/packages/shared/response-ops/recurring-schedule-form/converters/moment.test.ts new file mode 100644 index 0000000000000..53db3256e0b59 --- /dev/null +++ b/src/platform/packages/shared/response-ops/recurring-schedule-form/converters/moment.test.ts @@ -0,0 +1,62 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { + convertStringToMoment, + convertStringToMomentOptional, + convertMomentToString, + convertMomentToStringOptional, +} from './moment'; +import moment from 'moment'; + +describe('Moment converters', () => { + describe('convertStringToMoment', () => { + it('should convert ISO string to Moment', () => { + const dateStr = '2025-06-26T12:34:56.789Z'; + const result = convertStringToMoment(dateStr); + expect(moment.isMoment(result)).toBe(true); + expect(result.toISOString()).toBe(dateStr); + }); + }); + + describe('convertStringToMomentOptional', () => { + it('should convert ISO string to Moment if value is provided', () => { + const dateStr = '2025-06-26T12:34:56.789Z'; + const result = convertStringToMomentOptional(dateStr); + expect(moment.isMoment(result)).toBe(true); + expect(result?.toISOString()).toBe(dateStr); + }); + + it('should return undefined if value is not provided', () => { + const result = convertStringToMomentOptional(undefined); + expect(result).toBeUndefined(); + }); + }); + + describe('convertMomentToString', () => { + it('should convert Moment to ISO string', () => { + const m = moment('2025-06-26T12:34:56.789Z'); + const result = convertMomentToString(m); + expect(result).toBe('2025-06-26T12:34:56.789Z'); + }); + }); + + describe('convertMomentToStringOptional', () => { + it('should convert Moment to ISO string if value is provided', () => { + const m = moment('2025-06-26T12:34:56.789Z'); + const result = convertMomentToStringOptional(m); + expect(result).toBe('2025-06-26T12:34:56.789Z'); + }); + + it('should return empty string if value is not provided', () => { + const result = convertMomentToStringOptional(undefined); + expect(result).toBe(''); + }); + }); +}); diff --git a/src/platform/packages/shared/response-ops/recurring-schedule-form/converters/moment.ts b/src/platform/packages/shared/response-ops/recurring-schedule-form/converters/moment.ts new file mode 100644 index 0000000000000..b3d31feedd89a --- /dev/null +++ b/src/platform/packages/shared/response-ops/recurring-schedule-form/converters/moment.ts @@ -0,0 +1,20 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { Moment } from 'moment'; +import moment from 'moment'; + +export const convertStringToMoment = (value: string): Moment => moment(value); + +export const convertStringToMomentOptional = (value?: string): Moment | undefined => + value ? moment(value) : undefined; + +export const convertMomentToString = (value: Moment): string => value?.toISOString(); + +export const convertMomentToStringOptional = (value?: Moment): string => value?.toISOString() ?? ''; diff --git a/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.test.ts b/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.test.ts index 017645e8a933c..82e028783fe3a 100644 --- a/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.test.ts +++ b/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.test.ts @@ -14,13 +14,13 @@ import { convertToRRule } from './convert_to_rrule'; describe('convertToRRule', () => { const timezone = 'UTC'; const today = '2023-03-22'; - const startDate = moment(today); + const startDate = moment(today).toISOString(); test('should convert a recurring schedule that is not recurring', () => { const rRule = convertToRRule({ startDate, timezone }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.YEARLY, count: 1, @@ -39,7 +39,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.DAILY, interval: 1, @@ -61,7 +61,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.DAILY, interval: 1, @@ -83,7 +83,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.DAILY, interval: 1, @@ -103,7 +103,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.WEEKLY, interval: 1, @@ -122,7 +122,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.MONTHLY, interval: 1, @@ -141,7 +141,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.YEARLY, interval: 1, @@ -163,7 +163,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.DAILY, interval: 1, @@ -184,7 +184,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.WEEKLY, interval: 1, @@ -206,7 +206,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.MONTHLY, interval: 1, @@ -228,7 +228,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.MONTHLY, interval: 1, @@ -249,7 +249,7 @@ describe('convertToRRule', () => { }); expect(rRule).toEqual({ - dtstart: startDate.toISOString(), + dtstart: startDate, tzid: 'UTC', freq: Frequency.YEARLY, interval: 3, diff --git a/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.ts b/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.ts index 147d248d532ab..d0f40258a2b7c 100644 --- a/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.ts +++ b/src/platform/packages/shared/response-ops/recurring-schedule-form/utils/convert_to_rrule.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { Moment } from 'moment'; +import moment from 'moment'; import { Frequency } from '@kbn/rrule'; import { ISO_WEEKDAYS_TO_RRULE } from '../constants'; import { getPresets } from './get_presets'; @@ -21,20 +21,21 @@ export const convertToRRule = ({ recurringSchedule, includeTime = false, }: { - startDate: Moment; + startDate: string; timezone: string; recurringSchedule?: RecurringSchedule; includeTime?: boolean; }): RRuleParams => { - const presets = getPresets(startDate); + const startDateMoment = moment(startDate); + const presets = getPresets(startDateMoment); const parsedSchedule = parseSchedule(recurringSchedule); const rRule: RRuleParams = { - dtstart: startDate.toISOString(), + dtstart: startDateMoment.toISOString(), tzid: timezone, ...(Boolean(includeTime) - ? { byhour: [startDate.get('hour')], byminute: [startDate.get('minute')] } + ? { byhour: [startDateMoment.get('hour')], byminute: [startDateMoment.get('minute')] } : {}), }; @@ -74,16 +75,16 @@ export const convertToRRule = ({ if (form.bymonth) { if (form.bymonth === 'day') { - rRule.bymonthday = [startDate.date()]; + rRule.bymonthday = [startDateMoment.date()]; } else if (form.bymonth === 'weekday') { - rRule.byweekday = [getNthByWeekday(startDate)]; + rRule.byweekday = [getNthByWeekday(startDateMoment)]; } } if (frequency === Frequency.YEARLY) { // rRule expects 1 based indexing for months - rRule.bymonth = [startDate.month() + 1]; - rRule.bymonthday = [startDate.date()]; + rRule.bymonth = [startDateMoment.month() + 1]; + rRule.bymonthday = [startDateMoment.date()]; } return rRule; diff --git a/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.test.tsx b/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.test.tsx index 82978314287b2..58e8364d5106a 100644 --- a/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.test.tsx +++ b/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.test.tsx @@ -6,17 +6,19 @@ */ import React, { PropsWithChildren } from 'react'; +import moment from 'moment'; import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { type ReportingAPIClient, useKibana } from '@kbn/reporting-public'; +import { coreMock } from '@kbn/core/public/mocks'; import { ReportTypeData, ScheduledReport } from '../../types'; import { getReportingHealth } from '../apis/get_reporting_health'; -import { coreMock } from '@kbn/core/public/mocks'; import { testQueryClient } from '../test_utils/test_query_client'; import { QueryClientProvider } from '@tanstack/react-query'; import { ScheduledReportFlyoutContent } from './scheduled_report_flyout_content'; import { scheduleReport } from '../apis/schedule_report'; import { ScheduledReportApiJSON } from '../../../server/types'; -import userEvent from '@testing-library/user-event'; +import * as useDefaultTimezoneModule from '../hooks/use_default_timezone'; // Mock Kibana hooks and context jest.mock('@kbn/reporting-public', () => ({ @@ -139,6 +141,10 @@ const mockKibanaServices = { getCurrent: jest.fn().mockResolvedValue({ user: { email: TEST_EMAIL } }), }, }; +const defaultTimezone = moment.tz.guess(); +const timezoneSpy = jest + .spyOn(useDefaultTimezoneModule, 'useDefaultTimezone') + .mockReturnValue({ defaultTimezone, isBrowser: true }); describe('ScheduledReportFlyoutContent', () => { beforeEach(() => { @@ -379,4 +385,63 @@ describe('ScheduledReportFlyoutContent', () => { expect(mockValidateEmailAddresses).toHaveBeenCalled(); expect(emailInput).not.toBeValid(); }); + + it('should use default values for startDate and timezone if not provided', async () => { + const systemTime = moment('2025-07-01'); + jest.useFakeTimers().setSystemTime(systemTime.toDate()); + + render( + + + + ); + + const timezoneField = await screen.findByTestId('timezoneCombobox'); + expect(within(timezoneField).getByText(defaultTimezone)).toBeInTheDocument(); + + const startDatePicker = await screen.findByTestId('startDatePicker'); + const startDateInput = within(startDatePicker).getByRole('textbox'); + const startDateValue = startDateInput.getAttribute('value')!; + expect(startDateValue).toEqual(systemTime.format('MM/DD/YYYY hh:mm A')); + + timezoneSpy.mockRestore(); + jest.useRealTimers(); + }); + + it('should show a validation error if startDate is in the past', async () => { + const systemTime = moment('2025-07-02'); + jest.useFakeTimers().setSystemTime(systemTime.toDate()); + + render( + + + + ); + + const startDatePicker = await screen.findByTestId('startDatePicker'); + const startDateInput = within(startDatePicker).getByRole('textbox'); + fireEvent.change(startDateInput, { target: { value: '07/01/2025 10:00 AM' } }); + fireEvent.blur(startDateInput); + + expect(await screen.findByText('Start date must be in the future')).toBeInTheDocument(); + + timezoneSpy.mockRestore(); + jest.useRealTimers(); + }); }); diff --git a/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.tsx b/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.tsx index e7ab3a324a285..ac9ca25571b11 100644 --- a/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.tsx +++ b/x-pack/platform/plugins/private/reporting/public/management/components/scheduled_report_flyout_content.tsx @@ -6,7 +6,7 @@ */ import React, { useEffect, useMemo } from 'react'; -import moment from 'moment'; +import moment, { Moment } from 'moment'; import { EuiBetaBadge, EuiButton, @@ -17,6 +17,7 @@ import { EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, + EuiFormLabel, EuiLink, EuiLoadingSpinner, EuiSpacer, @@ -39,6 +40,12 @@ import { mountReactNode } from '@kbn/core-mount-utils-browser-internal'; import { RecurringScheduleFormFields } from '@kbn/response-ops-recurring-schedule-form/components/recurring_schedule_form_fields'; import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { Frequency } from '@kbn/rrule'; +import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { TIMEZONE_OPTIONS as UI_TIMEZONE_OPTIONS } from '@kbn/core-ui-settings-common'; +import { + convertStringToMoment, + convertMomentToString, +} from '@kbn/response-ops-recurring-schedule-form/converters/moment'; import { useGetUserProfileQuery } from '../hooks/use_get_user_profile_query'; import { ResponsiveFormGroup } from './responsive_form_group'; import { getReportParams } from '../report_params'; @@ -49,15 +56,25 @@ import { useGetReportingHealthQuery } from '../hooks/use_get_reporting_health_qu import { ReportTypeData, ScheduledReport } from '../../types'; import * as i18n from '../translations'; import { SCHEDULED_REPORT_FORM_ID } from '../constants'; +import { getStartDateValidator } from '../validators/start_date_validator'; + +const { emptyField } = fieldValidators; const FormField = getUseField({ component: Field, }); +const TIMEZONE_OPTIONS = UI_TIMEZONE_OPTIONS.map((tz) => ({ + inputDisplay: tz, + value: tz, +})) ?? [{ text: 'UTC', value: 'UTC' }]; + export type FormData = Pick< ScheduledReport, | 'title' | 'reportTypeId' + | 'startDate' + | 'timezone' | 'recurringSchedule' | 'sendByEmail' | 'emailRecipients' @@ -119,8 +136,6 @@ export const ScheduledReportFlyoutContent = ({ http, }); const { defaultTimezone } = useDefaultTimezone(); - const now = useMemo(() => moment().tz(defaultTimezone), [defaultTimezone]); - const defaultStartDateValue = useMemo(() => now.toISOString(), [now]); const schema = useMemo( () => getScheduledReportFormSchema( @@ -130,8 +145,6 @@ export const ScheduledReportFlyoutContent = ({ [availableReportTypes, validateEmailAddresses] ); const recurring = true; - const startDate = defaultStartDateValue; - const timezone = defaultTimezone; const { form } = useForm({ defaultValue: scheduledReport, options: { stripEmptyFields: true }, @@ -141,14 +154,15 @@ export const ScheduledReportFlyoutContent = ({ const { title, reportTypeId, + startDate, + timezone, recurringSchedule, optimizedForPrinting, sendByEmail, emailRecipients, } = formData; - // Remove start date since it's not supported for now - const { dtstart, ...rrule } = convertToRRule({ - startDate: now, + const rrule = convertToRRule({ + startDate, timezone, recurringSchedule, includeTime: true, @@ -187,10 +201,12 @@ export const ScheduledReportFlyoutContent = ({ } }, }); - const [{ reportTypeId, sendByEmail }] = useFormData({ + const [{ reportTypeId, startDate, timezone, sendByEmail }] = useFormData({ form, - watch: ['reportTypeId', 'sendByEmail'], + watch: ['reportTypeId', 'startDate', 'timezone', 'sendByEmail'], }); + const now = useMemo(() => moment().set({ second: 0, millisecond: 0 }), []); + const defaultStartDateValue = useMemo(() => now.toISOString(), [now]); useEffect(() => { if (!readOnly && !hasManageReportingPrivilege && userProfile?.user.email) { @@ -302,17 +318,79 @@ export const ScheduledReportFlyoutContent = ({ {i18n.SCHEDULED_REPORT_FORM_SCHEDULE_SECTION_TITLE}} > + + path="startDate" + config={{ + type: FIELD_TYPES.DATE_PICKER, + label: i18n.SCHEDULED_REPORT_FORM_START_DATE_LABEL, + defaultValue: defaultStartDateValue, + serializer: convertMomentToString, + deserializer: convertStringToMoment, + validations: [ + { + validator: emptyField(i18n.SCHEDULED_REPORT_FORM_START_DATE_REQUIRED_MESSAGE), + }, + { + validator: getStartDateValidator(now, timezone ?? defaultTimezone), + }, + ], + }} + componentProps={{ + compressed: true, + fullWidth: true, + 'data-test-subj': 'startDatePicker', + euiFieldProps: { + compressed: true, + fullWidth: true, + showTimeSelect: true, + minDate: now, + readOnly, + }, + }} + /> + + {i18n.SCHEDULED_REPORT_FORM_TIMEZONE_LABEL} + + ), + readOnly, + }, + }} + /> {isRecurring && ( - + <> + + + )} { + const timezone = 'UTC'; + const today = moment.tz('2025-07-11T00:00:00Z', timezone); + const validator = getStartDateValidator(today, timezone); + + it('returns error if value is before today', () => { + const value = moment.tz('2025-07-10T23:59:59Z', timezone); + const result = validator({ value } as any); + expect(result).toEqual({ message: SCHEDULED_REPORT_FORM_START_DATE_TOO_EARLY_MESSAGE }); + }); + + it('returns undefined if value is equal to today', () => { + const value = moment.tz('2025-07-11T00:00:00Z', timezone); + const result = validator({ value } as any); + expect(result).toBeUndefined(); + }); + + it('returns undefined if value is after today', () => { + const value = moment.tz('2025-07-12T00:00:00Z', timezone); + const result = validator({ value } as any); + expect(result).toBeUndefined(); + }); + + it('handles different timezones correctly', () => { + const tz = 'America/New_York'; + const todayNY = moment.tz('2025-07-11T00:00:00', tz); + const validatorNY = getStartDateValidator(todayNY, tz); + const value = moment.tz('2025-07-10T23:59:59', tz); + const result = validatorNY({ value } as any); + expect(result).toEqual({ message: SCHEDULED_REPORT_FORM_START_DATE_TOO_EARLY_MESSAGE }); + }); +}); diff --git a/x-pack/platform/plugins/private/reporting/public/management/validators/start_date_validator.ts b/x-pack/platform/plugins/private/reporting/public/management/validators/start_date_validator.ts index 4555b4f1edf9e..121d1de901f41 100644 --- a/x-pack/platform/plugins/private/reporting/public/management/validators/start_date_validator.ts +++ b/x-pack/platform/plugins/private/reporting/public/management/validators/start_date_validator.ts @@ -11,9 +11,10 @@ import { SCHEDULED_REPORT_FORM_START_DATE_TOO_EARLY_MESSAGE } from '../translati import { ScheduledReport } from '../../types'; export const getStartDateValidator = - (today: Moment): ValidationFunc => + (today: Moment, timezone: string): ValidationFunc, string, Moment> => ({ value }) => { - if (value.isBefore(today)) { + const valueInTimezone = value.clone().tz(timezone, true); + if (valueInTimezone.isBefore(today)) { return { message: SCHEDULED_REPORT_FORM_START_DATE_TOO_EARLY_MESSAGE, }; diff --git a/x-pack/platform/plugins/private/reporting/public/types.ts b/x-pack/platform/plugins/private/reporting/public/types.ts index af4b40e02a66e..9286ffa9e1fe6 100644 --- a/x-pack/platform/plugins/private/reporting/public/types.ts +++ b/x-pack/platform/plugins/private/reporting/public/types.ts @@ -54,21 +54,43 @@ export interface JobSummarySet { export type ReportTypeId = 'pngV2' | 'printablePdfV2' | 'csv_searchsource' | 'csv_v2'; export interface ScheduledReport { + /** + * The title of the report, used for the filename and in the UI + */ title: string; + /** + * The type of report to generate, e.g. 'pngV2', 'printablePdfV2', 'csv_searchsource' + */ reportTypeId: ReportTypeId; + /** + * PDF-specific option + * TODO move this to a more specific interface + */ optimizedForPrinting?: boolean; + /** + * The date when the report should be first generated + */ + startDate: string; + /** + * The timezone associated with the dates + */ + timezone: string; + /** + * Whether the report should be generated on a recurring schedule + */ recurring: boolean; + /** + * If recurring, the schedule for generating the report + */ recurringSchedule: RecurringSchedule; - sendByEmail: boolean; - emailRecipients: string[]; /** - * @internal Still unsupported by the schedule API + * Boolean indicating whether the report should be sent by email */ - startDate?: string; + sendByEmail: boolean; /** - * @internal Still unsupported by the schedule API + * List of email addresses to send the report to (`to` field in the email) */ - timezone?: string; + emailRecipients: string[]; } export interface ReportTypeData { diff --git a/x-pack/platform/plugins/private/reporting/tsconfig.json b/x-pack/platform/plugins/private/reporting/tsconfig.json index 61c4266ab83ff..bd7bdca9d183f 100644 --- a/x-pack/platform/plugins/private/reporting/tsconfig.json +++ b/x-pack/platform/plugins/private/reporting/tsconfig.json @@ -65,7 +65,8 @@ "@kbn/core-http-browser", "@kbn/response-ops-recurring-schedule-form", "@kbn/core-mount-utils-browser-internal", - "@kbn/core-user-profile-browser" + "@kbn/core-user-profile-browser", + "@kbn/core-ui-settings-common" ], "exclude": ["target/**/*"] } diff --git a/x-pack/platform/plugins/shared/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx b/x-pack/platform/plugins/shared/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx index 2670993aa2e2b..fc1ddfb52f81d 100644 --- a/x-pack/platform/plugins/shared/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx +++ b/x-pack/platform/plugins/shared/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx @@ -168,7 +168,7 @@ export const CreateMaintenanceWindowForm = React.memo