Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Daylight saving time calendar events #193605

Merged
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
635bc9f
[ML] Daylight saving time calendar events
jgowdyelastic Sep 20, 2024
08712f4
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Sep 24, 2024
73a7d36
fixes after merge with main
jgowdyelastic Sep 24, 2024
9cf2c1e
translations
jgowdyelastic Sep 24, 2024
18b6985
fixing paths to edit calendar
jgowdyelastic Sep 24, 2024
54ec6b3
fixing jest tests
jgowdyelastic Sep 24, 2024
2386227
translations
jgowdyelastic Sep 25, 2024
e46008b
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Sep 25, 2024
47f90ec
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Sep 26, 2024
8bb0914
adding dst calendar to job wizards
jgowdyelastic Sep 26, 2024
143f632
fixing link to management list
jgowdyelastic Sep 26, 2024
a610b67
settings layout
jgowdyelastic Sep 26, 2024
8c3c930
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Sep 30, 2024
c2ce577
snapshot
jgowdyelastic Oct 1, 2024
a7e4c5d
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 1, 2024
9f56e20
start and end tooltips
jgowdyelastic Oct 1, 2024
a68823c
adding tests
jgowdyelastic Oct 1, 2024
958a4d7
text update
jgowdyelastic Oct 2, 2024
14dd326
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 2, 2024
5af19ac
snapshots
jgowdyelastic Oct 2, 2024
0bfc6a8
fixing test
jgowdyelastic Oct 2, 2024
5c4e367
Merge branch 'daylight-savings-calendar-events' of github.com:jgowdye…
jgowdyelastic Oct 2, 2024
2d0bb82
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 3, 2024
4d5ef3a
small changes based on review
jgowdyelastic Oct 3, 2024
db72ef0
removing generate button
jgowdyelastic Oct 3, 2024
8b636dc
translations
jgowdyelastic Oct 3, 2024
5b1a167
fixing bug with job wizard
jgowdyelastic Oct 3, 2024
65a40dc
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 3, 2024
70fa935
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 4, 2024
b2ce67e
snapshots
jgowdyelastic Oct 4, 2024
fea06b1
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 4, 2024
1a6b4c4
Merge branch 'main' into daylight-savings-calendar-events
jgowdyelastic Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions x-pack/plugins/ml/common/constants/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ export const ML_PAGES = {
ANOMALY_DETECTION_MODULES_VIEW_OR_CREATE: 'modules/check_view_or_create',
SETTINGS: 'settings',
CALENDARS_MANAGE: 'settings/calendars_list',
CALENDARS_DST_MANAGE: 'settings/calendars_dst_list',
CALENDARS_NEW: 'settings/calendars_list/new_calendar',
CALENDARS_DST_NEW: 'settings/calendars_dst_list/new_calendar',
CALENDARS_EDIT: 'settings/calendars_list/edit_calendar',
CALENDARS_DST_EDIT: 'settings/calendars_dst_list/edit_calendar',
FILTER_LISTS_MANAGE: 'settings/filter_lists',
FILTER_LISTS_NEW: 'settings/filter_lists/new_filter_list',
FILTER_LISTS_EDIT: 'settings/filter_lists/edit_filter_list',
Expand Down
18 changes: 13 additions & 5 deletions x-pack/plugins/ml/common/types/calendars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@
* 2.0.
*/

export type CalendarId = string;
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';

export interface Calendar {
calendar_id: CalendarId;
export type MlCalendarId = string;

export interface MlCalendar {
calendar_id: MlCalendarId;
description: string;
events: any[];
job_ids: string[];
total_job_count?: number;
}

export interface UpdateCalendar extends Calendar {
calendarId: CalendarId;
export interface UpdateCalendar extends MlCalendar {
calendarId: MlCalendarId;
}

export type MlCalendarEvent = estypes.MlCalendarEvent & {
force_time_shift?: number;
skip_result?: boolean;
skip_model_update?: boolean;
};
11 changes: 11 additions & 0 deletions x-pack/plugins/ml/common/types/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export type MlGenericUrlState = MLPageState<
| typeof ML_PAGES.DATA_FRAME_ANALYTICS_CREATE_JOB
| typeof ML_PAGES.OVERVIEW
| typeof ML_PAGES.CALENDARS_MANAGE
| typeof ML_PAGES.CALENDARS_DST_MANAGE
| typeof ML_PAGES.CALENDARS_NEW
| typeof ML_PAGES.CALENDARS_DST_NEW
| typeof ML_PAGES.FILTER_LISTS_MANAGE
| typeof ML_PAGES.FILTER_LISTS_NEW
| typeof ML_PAGES.SETTINGS
Expand Down Expand Up @@ -247,6 +249,14 @@ export type CalendarEditUrlState = MLPageState<
}
>;

export type CalendarDstEditUrlState = MLPageState<
typeof ML_PAGES.CALENDARS_DST_EDIT,
{
calendarId: string;
globalState?: MlCommonGlobalState;
}
>;

export type FilterEditUrlState = MLPageState<
typeof ML_PAGES.FILTER_LISTS_EDIT,
{
Expand Down Expand Up @@ -277,6 +287,7 @@ export type MlLocatorState =
| DataFrameAnalyticsUrlState
| DataFrameAnalyticsExplorationUrlState
| CalendarEditUrlState
| CalendarDstEditUrlState
| FilterEditUrlState
| MlGenericUrlState
| NotificationsUrlState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import type { CREATED_BY_LABEL } from '../../../../../../common/constants/new_jo
import { JOB_TYPE, SHARED_RESULTS_INDEX_NAME } from '../../../../../../common/constants/new_job';
import { collectAggs } from './util/general';
import { filterRuntimeMappings } from './util/filter_runtime_mappings';
import type { Calendar } from '../../../../../../common/types/calendars';
import type { MlCalendar } from '../../../../../../common/types/calendars';
import { mlCalendarService } from '../../../../services/calendar_service';
import { getDatafeedAggregations } from '../../../../../../common/util/datafeed_utils';
import { getFirstKeyInObject } from '../../../../../../common/util/object_utils';
Expand All @@ -58,7 +58,7 @@ export class JobCreator {
protected _indexPatternTitle: IndexPatternTitle = '';
protected _indexPatternDisplayName: string = '';
protected _job_config: Job;
protected _calendars: Calendar[];
protected _calendars: MlCalendar[];
protected _datafeed_config: Datafeed;
protected _detectors: Detector[];
protected _influencers: string[];
Expand Down Expand Up @@ -271,11 +271,11 @@ export class JobCreator {
this._job_config.groups = groups;
}

public get calendars(): Calendar[] {
public get calendars(): MlCalendar[] {
return this._calendars;
}

public set calendars(calendars: Calendar[]) {
public set calendars(calendars: MlCalendar[]) {
this._calendars = calendars;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,16 @@ export const AdditionalSection: FC<Props> = ({ additionalExpanded, setAdditional
<CustomUrlsSelection />
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer />

<EuiFlexGroup gutterSize="xl" style={{ marginLeft: '0px', marginRight: '0px' }}>
<EuiFlexItem>
<CalendarsSelection />
</EuiFlexItem>
<EuiFlexItem />
<EuiFlexItem>
<CalendarsSelection isDst={true} />
</EuiFlexItem>
</EuiFlexGroup>
</section>
</EuiAccordion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,21 @@ import {
EuiToolTip,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { separateCalendarsByType } from '../../../../../../../../../settings/calendars/dst_utils';
import { JobCreatorContext } from '../../../../../job_creator_context';
import { Description } from './description';
import { PLUGIN_ID } from '../../../../../../../../../../../common/constants/app';
import type { Calendar } from '../../../../../../../../../../../common/types/calendars';
import type { MlCalendar } from '../../../../../../../../../../../common/types/calendars';
import { useMlApi, useMlKibana } from '../../../../../../../../../contexts/kibana';
import { GLOBAL_CALENDAR } from '../../../../../../../../../../../common/constants/calendars';
import { ML_PAGES } from '../../../../../../../../../../../common/constants/locator';
import { DescriptionDst } from './description_dst';

export const CalendarsSelection: FC = () => {
interface Props {
isDst?: boolean;
}

export const CalendarsSelection: FC<Props> = ({ isDst = false }) => {
const {
services: {
application: { getUrlForApp },
Expand All @@ -37,19 +43,20 @@ export const CalendarsSelection: FC = () => {
const mlApi = useMlApi();

const { jobCreator, jobCreatorUpdate } = useContext(JobCreatorContext);
const [selectedCalendars, setSelectedCalendars] = useState<Calendar[]>(jobCreator.calendars);
const [selectedOptions, setSelectedOptions] = useState<Array<EuiComboBoxOptionOption<Calendar>>>(
[]
);
const [options, setOptions] = useState<Array<EuiComboBoxOptionOption<Calendar>>>([]);
const [selectedCalendars, setSelectedCalendars] = useState<MlCalendar[]>(jobCreator.calendars);
const [selectedOptions, setSelectedOptions] = useState<
Array<EuiComboBoxOptionOption<MlCalendar>>
>([]);
const [options, setOptions] = useState<Array<EuiComboBoxOptionOption<MlCalendar>>>([]);
const [isLoading, setIsLoading] = useState(false);

async function loadCalendars() {
setIsLoading(true);
const calendars = (await mlApi.calendars()).filter(
const { calendars, calendarsDst } = separateCalendarsByType(await mlApi.calendars());
const filteredCalendars = (isDst ? calendarsDst : calendars).filter(
(c) => c.job_ids.includes(GLOBAL_CALENDAR) === false
);
setOptions(calendars.map((c) => ({ label: c.calendar_id, value: c })));
setOptions(filteredCalendars.map((c) => ({ label: c.calendar_id, value: c })));
setSelectedOptions(selectedCalendars.map((c) => ({ label: c.calendar_id, value: c })));
setIsLoading(false);
}
Expand All @@ -65,7 +72,7 @@ export const CalendarsSelection: FC = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedCalendars.join()]);

const comboBoxProps: EuiComboBoxProps<Calendar> = {
const comboBoxProps: EuiComboBoxProps<MlCalendar> = {
peteharverson marked this conversation as resolved.
Show resolved Hide resolved
async: true,
options,
selectedOptions,
Expand All @@ -77,11 +84,13 @@ export const CalendarsSelection: FC = () => {
};

const manageCalendarsHref = getUrlForApp(PLUGIN_ID, {
path: ML_PAGES.CALENDARS_MANAGE,
path: isDst ? ML_PAGES.CALENDARS_DST_MANAGE : ML_PAGES.CALENDARS_MANAGE,
});

const Desc = isDst ? DescriptionDst : Description;

return (
<Description>
<Desc>
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiFlexItem>
<EuiComboBox {...comboBoxProps} data-test-subj="mlJobWizardComboBoxCalendars" />
Expand Down Expand Up @@ -119,6 +128,6 @@ export const CalendarsSelection: FC = () => {
/>
</EuiLink>
</EuiText>
</Description>
</Desc>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 type { FC, PropsWithChildren } from 'react';
import React, { memo } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiDescribedFormGroup, EuiFormRow, EuiLink } from '@elastic/eui';
import { useMlKibana } from '../../../../../../../../../contexts/kibana';

export const DescriptionDst: FC<PropsWithChildren<unknown>> = memo(({ children }) => {
const {
services: { docLinks },
} = useMlKibana();
const docsUrl = docLinks.links.ml.calendars;
const title = i18n.translate(
'xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsDstSelection.title',
{
defaultMessage: 'DST Calendars',
}
);
return (
<EuiDescribedFormGroup
title={<h3>{title}</h3>}
description={
<FormattedMessage
id="xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsDstSelection.description"
defaultMessage="A list of scheduled events you want to ignore, taking into account daylight saving time shifts. {learnMoreLink}"
values={{
learnMoreLink: (
<EuiLink href={docsUrl} target="_blank">
<FormattedMessage
id="xpack.ml.newJob.wizard.jobDetailsStep.additionalSection.calendarsSelection.learnMoreLinkText"
peteharverson marked this conversation as resolved.
Show resolved Hide resolved
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
}
>
<EuiFormRow>
<>{children}</>
</EuiFormRow>
</EuiDescribedFormGroup>
);
});
9 changes: 9 additions & 0 deletions x-pack/plugins/ml/public/application/routing/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ export const CALENDAR_MANAGEMENT_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
deepLinkId: 'ml:calendarSettings',
});

export const CALENDAR_DST_MANAGEMENT_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagementLabel', {
defaultMessage: 'Calendar DST management',
}),
href: '/settings/calendars_dst_list',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: I see that each breadcrumb is implemented this way, so it's not strictly related to the PR, but why aren't we using locator constants instead of plain strings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we probably should be using those here.
I believe these breadcrumb files pre-date the introduction of the locator constants.

deepLinkId: 'ml:calendarSettings',
});

export const FILTER_LISTS_BREADCRUMB: ChromeBreadcrumb = Object.freeze({
text: i18n.translate('xpack.ml.settings.breadcrumbs.filterListsLabel', {
defaultMessage: 'Filter lists',
Expand Down Expand Up @@ -160,6 +168,7 @@ const breadcrumbs = {
CHANGE_POINT_DETECTION,
CREATE_JOB_BREADCRUMB,
CALENDAR_MANAGEMENT_BREADCRUMB,
CALENDAR_DST_MANAGEMENT_BREADCRUMB,
FILTER_LISTS_BREADCRUMB,
SUPPLIED_CONFIGURATIONS,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const calendarListRouteFactory = (
title: i18n.translate('xpack.ml.settings.calendarList.docTitle', {
defaultMessage: 'Calendars',
}),
render: (props, deps) => <PageWrapper {...props} deps={deps} />,
render: (props, deps) => <PageWrapper {...props} deps={deps} isDst={false} />,
breadcrumbs: [
getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath),
getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath),
Expand All @@ -40,7 +40,24 @@ export const calendarListRouteFactory = (
],
});

const PageWrapper: FC<PageProps> = () => {
export const calendarDstListRouteFactory = (
navigateToPath: NavigateToPath,
basePath: string
): MlRoute => ({
path: createPath(ML_PAGES.CALENDARS_DST_MANAGE),
title: i18n.translate('xpack.ml.settings.calendarList.docTitle', {
defaultMessage: 'Calendars',
}),
render: (props, deps) => <PageWrapper {...props} deps={deps} isDst={true} />,
breadcrumbs: [
getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath),
getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath),
getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB', navigateToPath, basePath),
getBreadcrumbWithUrlForApp('CALENDAR_DST_MANAGEMENT_BREADCRUMB'),
],
});

const PageWrapper: FC<PageProps & { isDst: boolean }> = ({ isDst }) => {
const { context } = useRouteResolver('full', ['canGetCalendars'], { getMlNodeCount });

useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
Expand All @@ -52,7 +69,7 @@ const PageWrapper: FC<PageProps> = () => {

return (
<PageLoader context={context}>
<CalendarsList {...{ canCreateCalendar, canDeleteCalendar }} />
<CalendarsList {...{ canCreateCalendar, canDeleteCalendar, isDst }} />
</PageLoader>
);
};
Loading