diff --git a/x-pack/legacy/plugins/ml/common/constants/calendars.ts b/x-pack/legacy/plugins/ml/common/constants/calendars.ts
new file mode 100644
index 0000000000000..1a56257ca1304
--- /dev/null
+++ b/x-pack/legacy/plugins/ml/common/constants/calendars.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+export const GLOBAL_CALENDAR = '_all';
diff --git a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx
index 919972186761a..1e7327552623e 100644
--- a/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx
+++ b/x-pack/legacy/plugins/ml/public/application/jobs/new_job/pages/components/job_details_step/components/additional_section/components/calendars/calendars_selection.tsx
@@ -23,6 +23,7 @@ import { JobCreatorContext } from '../../../../../job_creator_context';
import { Description } from './description';
import { ml } from '../../../../../../../../../services/ml_api_service';
import { Calendar } from '../../../../../../../../../../../common/types/calendars';
+import { GLOBAL_CALENDAR } from '../../../../../../../../../../../common/constants/calendars';
export const CalendarsSelection: FC = () => {
const { jobCreator, jobCreatorUpdate } = useContext(JobCreatorContext);
@@ -35,7 +36,9 @@ export const CalendarsSelection: FC = () => {
async function loadCalendars() {
setIsLoading(true);
- const calendars = await ml.calendars();
+ const calendars = (await ml.calendars()).filter(
+ c => c.job_ids.includes(GLOBAL_CALENDAR) === false
+ );
setOptions(calendars.map(c => ({ label: c.calendar_id, value: c })));
setSelectedOptions(selectedCalendars.map(c => ({ label: c.calendar_id, value: c })));
setIsLoading(false);
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap
index 2f5eb596a157b..21f505cff9aec 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/__snapshots__/new_calendar.test.js.snap
@@ -22,6 +22,7 @@ exports[`NewCalendar Renders new calendar form 1`] = `
eventsList={Array []}
groupIds={Array []}
isEdit={false}
+ isGlobalCalendar={false}
isNewCalendarIdValid={true}
jobIds={Array []}
onCalendarIdChange={[Function]}
@@ -30,6 +31,7 @@ exports[`NewCalendar Renders new calendar form 1`] = `
onDescriptionChange={[Function]}
onEdit={[Function]}
onEventDelete={[Function]}
+ onGlobalCalendarChange={[Function]}
onGroupSelection={[Function]}
onJobSelection={[Function]}
saving={false}
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap
index 0e7db62e44b51..acce01f1994db 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/__snapshots__/calendar_form.test.js.snap
@@ -84,59 +84,19 @@ exports[`CalendarForm Renders calendar form 1`] = `
value=""
/>
-
- }
- labelType="label"
- >
-
-
-
+
}
- labelType="label"
- >
-
-
+ name="switch"
+ />
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js
index fffcdf4c516f8..62daced72ceb2 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/calendar_form/calendar_form.js
@@ -18,6 +18,7 @@ import {
EuiSpacer,
EuiText,
EuiTitle,
+ EuiSwitch,
} from '@elastic/eui';
import { EventsTable } from '../events_table';
@@ -68,6 +69,8 @@ export const CalendarForm = ({
selectedGroupOptions,
selectedJobOptions,
showNewEventModal,
+ isGlobalCalendar,
+ onGlobalCalendarChange,
}) => {
const msg = i18n.translate('xpack.ml.calendarsEdit.calendarForm.allowedCharactersDescription', {
defaultMessage:
@@ -81,7 +84,9 @@ export const CalendarForm = ({
return (
- {!isEdit && (
+ {isEdit === true ? (
+
+ ) : (
@@ -128,39 +133,59 @@ export const CalendarForm = ({
)}
- {isEdit && }
-
- }
- >
-
-
-
+
+
}
- >
-
-
+ checked={isGlobalCalendar}
+ onChange={onGlobalCalendarChange}
+ />
+
+ {isGlobalCalendar === false && (
+ <>
+
+
+
+ }
+ >
+
+
+
+
+ }
+ >
+
+
+ >
+ )}
@@ -240,4 +265,6 @@ CalendarForm.propTypes = {
selectedGroupOptions: PropTypes.array.isRequired,
selectedJobOptions: PropTypes.array.isRequired,
showNewEventModal: PropTypes.func.isRequired,
+ isGlobalCalendar: PropTypes.bool.isRequired,
+ onGlobalCalendarChange: PropTypes.func.isRequired,
};
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js
index 935e67ec05eff..815d1565d5bc4 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/new_calendar.js
@@ -19,6 +19,7 @@ import { NewEventModal } from './new_event_modal';
import { ImportModal } from './import_modal';
import { ml } from '../../../services/ml_api_service';
import { withKibana } from '../../../../../../../../../src/plugins/kibana_react/public';
+import { GLOBAL_CALENDAR } from '../../../../../common/constants/calendars';
class NewCalendarUI extends Component {
static propTypes = {
@@ -46,6 +47,7 @@ class NewCalendarUI extends Component {
events: [],
saving: false,
selectedCalendar: undefined,
+ isGlobalCalendar: false,
};
}
@@ -65,6 +67,7 @@ class NewCalendarUI extends Component {
let eventsList = [];
let selectedCalendar;
let formCalendarId = '';
+ let isGlobalCalendar = false;
// Editing existing calendar.
if (this.props.calendarId !== undefined) {
@@ -74,13 +77,17 @@ class NewCalendarUI extends Component {
formCalendarId = selectedCalendar.calendar_id;
eventsList = selectedCalendar.events;
- selectedCalendar.job_ids.forEach(id => {
- if (jobIds.find(jobId => jobId === id)) {
- selectedJobOptions.push({ label: id });
- } else if (groupIds.find(groupId => groupId === id)) {
- selectedGroupOptions.push({ label: id });
- }
- });
+ if (selectedCalendar.job_ids.includes(GLOBAL_CALENDAR)) {
+ isGlobalCalendar = true;
+ } else {
+ selectedCalendar.job_ids.forEach(id => {
+ if (jobIds.find(jobId => jobId === id)) {
+ selectedJobOptions.push({ label: id });
+ } else if (groupIds.find(groupId => groupId === id)) {
+ selectedGroupOptions.push({ label: id });
+ }
+ });
+ }
}
}
@@ -96,6 +103,7 @@ class NewCalendarUI extends Component {
selectedJobOptions,
selectedGroupOptions,
selectedCalendar,
+ isGlobalCalendar,
});
} catch (error) {
console.log(error);
@@ -181,10 +189,15 @@ class NewCalendarUI extends Component {
events,
selectedGroupOptions,
selectedJobOptions,
+ isGlobalCalendar,
} = this.state;
- const jobIds = selectedJobOptions.map(option => option.label);
- const groupIds = selectedGroupOptions.map(option => option.label);
+ const allIds = isGlobalCalendar
+ ? [GLOBAL_CALENDAR]
+ : [
+ ...selectedJobOptions.map(option => option.label),
+ ...selectedGroupOptions.map(option => option.label),
+ ];
// Reduce events to fields expected by api
const eventsToSave = events.map(event => ({
@@ -198,7 +211,7 @@ class NewCalendarUI extends Component {
calendarId: formCalendarId,
description,
events: eventsToSave,
- job_ids: [...jobIds, ...groupIds],
+ job_ids: allIds,
};
return calendar;
@@ -214,6 +227,12 @@ class NewCalendarUI extends Component {
}));
};
+ onGlobalCalendarChange = ({ currentTarget }) => {
+ this.setState({
+ isGlobalCalendar: currentTarget.checked,
+ });
+ };
+
onJobSelection = selectedJobOptions => {
this.setState({
selectedJobOptions,
@@ -295,6 +314,7 @@ class NewCalendarUI extends Component {
selectedCalendar,
selectedJobOptions,
selectedGroupOptions,
+ isGlobalCalendar,
} = this.state;
let modal = '';
@@ -351,6 +371,8 @@ class NewCalendarUI extends Component {
selectedJobOptions={selectedJobOptions}
onCreateGroupOption={this.onCreateGroupOption}
showNewEventModal={this.showNewEventModal}
+ isGlobalCalendar={isGlobalCalendar}
+ onGlobalCalendarChange={this.onGlobalCalendarChange}
/>
{modal}
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js
index e4ab6677accf5..efc54c181fdc1 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/edit/utils.js
@@ -73,14 +73,17 @@ function getCalendars() {
export function getCalendarSettingsData() {
return new Promise(async (resolve, reject) => {
try {
- const data = await Promise.all([getJobIds(), getGroupIds(), getCalendars()]);
+ const [jobIds, groupIds, calendars] = await Promise.all([
+ getJobIds(),
+ getGroupIds(),
+ getCalendars(),
+ ]);
- const formattedData = {
- jobIds: data[0],
- groupIds: data[1],
- calendars: data[2],
- };
- resolve(formattedData);
+ resolve({
+ jobIds,
+ groupIds,
+ calendars,
+ });
} catch (error) {
console.log(error);
reject(error);
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap
index ff74c592b2b0f..14b65a04ce599 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/__snapshots__/table.test.js.snap
@@ -16,6 +16,7 @@ exports[`CalendarsListTable renders the table with all calendars 1`] = `
Object {
"field": "job_ids_string",
"name": "Jobs",
+ "render": [Function],
"sortable": true,
"truncateText": true,
},
diff --git a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js
index bd1dafcd6c0aa..be41eabd5ae2d 100644
--- a/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js
+++ b/x-pack/legacy/plugins/ml/public/application/settings/calendars/list/table/table.js
@@ -12,6 +12,8 @@ import { EuiButton, EuiLink, EuiInMemoryTable } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
+import { GLOBAL_CALENDAR } from '../../../../../../common/constants/calendars';
+
export const CalendarsListTable = ({
calendarsList,
onDeleteClick,
@@ -52,6 +54,18 @@ export const CalendarsListTable = ({
}),
sortable: true,
truncateText: true,
+ render: jobList => {
+ return jobList === GLOBAL_CALENDAR ? (
+
+
+
+ ) : (
+ jobList
+ );
+ },
},
{
field: 'events_length',
diff --git a/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts b/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts
index 19f2eda466179..488839f68b3fe 100644
--- a/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts
+++ b/x-pack/legacy/plugins/ml/server/models/calendar/event_manager.ts
@@ -6,6 +6,8 @@
import Boom from 'boom';
+import { GLOBAL_CALENDAR } from '../../../common/constants/calendars';
+
export interface CalendarEvent {
calendar_id?: string;
event_id?: string;
@@ -32,7 +34,7 @@ export class EventManager {
// jobId is optional
async getAllEvents(jobId?: string) {
- const calendarId = '_all';
+ const calendarId = GLOBAL_CALENDAR;
try {
const resp = await this._client('ml.events', {
calendarId,
diff --git a/x-pack/legacy/plugins/ml/server/models/job_service/groups.js b/x-pack/legacy/plugins/ml/server/models/job_service/groups.js
index 91f82f04a9a0c..6fbc071ef9854 100644
--- a/x-pack/legacy/plugins/ml/server/models/job_service/groups.js
+++ b/x-pack/legacy/plugins/ml/server/models/job_service/groups.js
@@ -5,6 +5,7 @@
*/
import { CalendarManager } from '../calendar';
+import { GLOBAL_CALENDAR } from '../../../common/constants/calendars';
export function groupsProvider(callWithRequest) {
const calMngr = new CalendarManager(callWithRequest);
@@ -12,11 +13,13 @@ export function groupsProvider(callWithRequest) {
async function getAllGroups() {
const groups = {};
const jobIds = {};
- const [JOBS, CALENDARS] = [0, 1];
- const results = await Promise.all([callWithRequest('ml.jobs'), calMngr.getAllCalendars()]);
+ const [{ jobs }, calendars] = await Promise.all([
+ callWithRequest('ml.jobs'),
+ calMngr.getAllCalendars(),
+ ]);
- if (results[JOBS] && results[JOBS].jobs) {
- results[JOBS].jobs.forEach(job => {
+ if (jobs) {
+ jobs.forEach(job => {
jobIds[job.job_id] = null;
if (job.groups !== undefined) {
job.groups.forEach(g => {
@@ -33,10 +36,11 @@ export function groupsProvider(callWithRequest) {
}
});
}
- if (results[CALENDARS]) {
- results[CALENDARS].forEach(cal => {
+ if (calendars) {
+ calendars.forEach(cal => {
cal.job_ids.forEach(jId => {
- if (jobIds[jId] === undefined) {
+ // don't include _all in the calendar groups list
+ if (jId !== GLOBAL_CALENDAR && jobIds[jId] === undefined) {
if (groups[jId] === undefined) {
groups[jId] = {
id: jId,