From ebcb88cb1b1fe696c7b56cafb6f7ec9ab4162b10 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Fri, 2 Aug 2024 17:24:26 +0200 Subject: [PATCH] more cleanup --- .../rule_editor/rule_editor_flyout.test.js | 6 +- ...explorer_chart_config_builder.test.js.snap | 53 --------------- .../close_jobs_confirm_modal.tsx | 8 ++- .../stop_datafeeds_confirm_modal.tsx | 8 ++- .../datafeed_chart_flyout.tsx | 11 ++-- .../delete_job_modal/delete_job_modal.tsx | 7 ++ .../edit_job_flyout/edit_job_flyout.js | 8 +-- .../edit_job_flyout/tabs/detectors.js | 14 +++- .../components/job_actions/management.js | 3 +- .../jobs_list_view/jobs_list_view.js | 2 +- .../multi_job_actions/actions_menu.js | 26 ++++++-- .../group_selector/group_selector.js | 14 ++-- .../reset_job_modal/reset_job_modal.tsx | 8 ++- .../start_datafeed_modal.js | 25 +++++-- .../jobs/jobs_list/components/utils.d.ts | 66 +++++++++++++++---- .../jobs/jobs_list/components/utils.js | 53 +++++++++------ .../timeseriesexplorer/state_manager.tsx | 2 +- .../application/services/job_service.js | 6 +- .../delete_filter_list_modal.js | 5 +- .../delete_filter_lists.js | 5 +- .../filter_lists/edit/edit_filter_list.js | 8 ++- .../settings/filter_lists/edit/utils.js | 8 +-- .../timeseriesexplorer.d.ts | 17 ++--- .../timeseriesexplorer/timeseriesexplorer.js | 2 +- .../util/time_series_explorer_service.ts | 4 +- 25 files changed, 220 insertions(+), 149 deletions(-) delete mode 100644 x-pack/plugins/ml/public/application/explorer/explorer_charts/__snapshots__/explorer_chart_config_builder.test.js.snap diff --git a/x-pack/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.test.js b/x-pack/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.test.js index 67ace1427eb13ef..8dce7f8f45f780b 100644 --- a/x-pack/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.test.js +++ b/x-pack/plugins/ml/public/application/components/rule_editor/rule_editor_flyout.test.js @@ -7,7 +7,7 @@ // Mock the services required for reading and writing job data. jest.mock('../../services/job_service', () => ({ - mlJobService: { + mlJobServiceFactory: () => ({ getJob: () => { return { job_id: 'farequote_no_by', @@ -43,9 +43,8 @@ jest.mock('../../services/job_service', () => ({ }, }; }, - }, + }), })); -jest.mock('../../services/ml_api_service', () => 'ml'); jest.mock('../../capabilities/check_capabilities', () => ({ checkPermission: () => true, })); @@ -93,6 +92,7 @@ function prepareTest() { }, }, }, + mlServices: { mlApiServices: {} }, notifications: { toasts: { addDanger: () => {}, diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/__snapshots__/explorer_chart_config_builder.test.js.snap b/x-pack/plugins/ml/public/application/explorer/explorer_charts/__snapshots__/explorer_chart_config_builder.test.js.snap deleted file mode 100644 index e2e1140f5c5b42c..000000000000000 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/__snapshots__/explorer_chart_config_builder.test.js.snap +++ /dev/null @@ -1,53 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`buildConfig get dataConfig for anomaly record 1`] = ` -Object { - "bucketSpanSeconds": 900, - "datafeedConfig": Object { - "chunking_config": Object { - "mode": "auto", - }, - "datafeed_id": "datafeed-mock-job-id", - "indices": Array [ - "farequote-2017", - ], - "job_id": "mock-job-id", - "query": Object { - "match_all": Object { - "boost": 1, - }, - }, - "query_delay": "86658ms", - "scroll_size": 1000, - "state": "stopped", - }, - "detectorIndex": 0, - "detectorLabel": "mean(responsetime)", - "entityFields": Array [ - Object { - "fieldName": "airline", - "fieldType": "partition", - "fieldValue": "JAL", - }, - ], - "fieldName": "responsetime", - "functionDescription": "mean", - "infoTooltip": Object { - "aggregationInterval": "15m", - "chartFunction": "avg responsetime", - "entityFields": Array [ - Object { - "fieldName": "airline", - "fieldValue": "JAL", - }, - ], - "jobId": "mock-job-id", - }, - "interval": "15m", - "jobId": "mock-job-id", - "metricFieldName": "responsetime", - "metricFunction": "avg", - "summaryCountFieldName": undefined, - "timeField": "@timestamp", -} -`; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx index 77b5cb6bcef550c..605ebc0a412ea3e 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx @@ -19,6 +19,7 @@ import { EuiButton, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useMlKibana } from '../../../../contexts/kibana'; import type { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; import { isManagedJob } from '../../../jobs_utils'; import { useMlJobService } from '../../../../services/job_service'; @@ -38,6 +39,11 @@ export const CloseJobsConfirmModal: FC = ({ unsetShowFunction, refreshJobs, }) => { + const { + services: { + notifications: { toasts }, + }, + } = useMlKibana(); const mlJobService = useMlJobService(); const [modalVisible, setModalVisible] = useState(false); const [hasManagedJob, setHasManaged] = useState(true); @@ -115,7 +121,7 @@ export const CloseJobsConfirmModal: FC = ({ { - closeJobs(mlJobService, jobsToReset, refreshJobs); + closeJobs(toasts, mlJobService, jobsToReset, refreshJobs); closeModal(); }} fill diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx index 445c40b605a69fa..265e0c58986aa6b 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx @@ -19,6 +19,7 @@ import { EuiButton, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useMlKibana } from '../../../../contexts/kibana'; import type { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; import { isManagedJob } from '../../../jobs_utils'; import { useMlJobService } from '../../../../services/job_service'; @@ -39,6 +40,11 @@ export const StopDatafeedsConfirmModal: FC = ({ unsetShowFunction, refreshJobs, }) => { + const { + services: { + notifications: { toasts }, + }, + } = useMlKibana(); const mlJobService = useMlJobService(); const [modalVisible, setModalVisible] = useState(false); const [hasManagedJob, setHasManaged] = useState(true); @@ -116,7 +122,7 @@ export const StopDatafeedsConfirmModal: FC = ({ { - stopDatafeeds(mlJobService, jobsToStop, refreshJobs); + stopDatafeeds(toasts, mlJobService, jobsToStop, refreshJobs); closeModal(); }} fill diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx index b8081bfcebed21e..510149ada47e6f8 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/datafeed_chart_flyout/datafeed_chart_flyout.tsx @@ -67,7 +67,6 @@ import { EditQueryDelay } from './edit_query_delay'; import type { ChartDirectionType } from './constants'; import { CHART_DIRECTION, CHART_SIZE } from './constants'; import { loadFullJob } from '../utils'; -import { useMlJobService } from '../../../../services/job_service'; import { checkPermission } from '../../../../capabilities/check_capabilities'; import { type ChartDataWithNullValues, fillMissingChartData } from './fill_missing_chart_data'; @@ -111,7 +110,7 @@ export const DatafeedChartFlyout: FC = ({ onClose, onModelSnapshotAnnotationClick, }) => { - const mlJobService = useMlJobService(); + const mlApiServices = useMlApiContext(); const [data, setData] = useState<{ datafeedConfig: CombinedJobWithStats['datafeed_config'] | undefined; bucketSpan: string | undefined; @@ -214,7 +213,7 @@ export const DatafeedChartFlyout: FC = ({ const getJobAndSnapshotData = useCallback(async () => { try { - const job: CombinedJobWithStats = await loadFullJob(mlJobService, jobId); + const job: CombinedJobWithStats = await loadFullJob(mlApiServices, jobId); const modelSnapshotResultsLine: LineAnnotationDatumWithModelSnapshot[] = []; const modelSnapshotsResp = await getModelSnapshots(jobId); const modelSnapshots = modelSnapshotsResp.model_snapshots ?? []; @@ -661,7 +660,7 @@ export const JobListDatafeedChartFlyout: FC = ( unsetShowFunction, refreshJobs, }) => { - const mlJobService = useMlJobService(); + const mlApiServices = useMlApiContext(); const [isVisible, setIsVisible] = useState(false); const [job, setJob] = useState(); const [jobWithStats, setJobWithStats] = useState(); @@ -678,10 +677,10 @@ export const JobListDatafeedChartFlyout: FC = ( const showRevertModelSnapshot = useCallback(async () => { // Need to load the full job with stats, as the model snapshot // flyout needs the timestamp of the last result. - const fullJob: CombinedJobWithStats = await loadFullJob(mlJobService, job!.id); + const fullJob: CombinedJobWithStats = await loadFullJob(mlApiServices, job!.id); setJobWithStats(fullJob); setIsRevertModelSnapshotFlyoutVisible(true); - // exclude mlJobservice from deps + // exclude mlApiServices from deps // eslint-disable-next-line react-hooks/exhaustive-deps }, [job]); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx index da6d1f645393c65..75d3fb270d226b6 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx @@ -23,6 +23,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useMlKibana } from '../../../../contexts/kibana'; import { deleteJobs } from '../utils'; import { BLOCKED_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list'; import { DeleteSpaceAwareItemCheckModal } from '../../../../components/delete_space_aware_item_check_modal'; @@ -40,6 +41,11 @@ interface Props { } export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, refreshJobs }) => { + const { + services: { + notifications: { toasts }, + }, + } = useMlKibana(); const mlJobService = useMlJobService(); const [deleting, setDeleting] = useState(false); const [modalVisible, setModalVisible] = useState(false); @@ -85,6 +91,7 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, const deleteJob = useCallback(() => { setDeleting(true); deleteJobs( + toasts, mlJobService, jobIds.map((id) => ({ id })), deleteUserAnnotations, diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js index faa6ce69ebec58f..6fef6134601e7b4 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js @@ -10,6 +10,7 @@ import React, { Component } from 'react'; import { cloneDeep, isEqual, pick } from 'lodash'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { withKibana } from '@kbn/kibana-react-plugin/public'; import { EuiButton, EuiButtonEmpty, @@ -30,7 +31,6 @@ import { saveJob } from './edit_utils'; import { loadFullJob } from '../utils'; import { validateModelMemoryLimit, validateGroupNames } from '../validate_job'; import { toastNotificationServiceProvider } from '../../../../services/toast_notification_service'; -import { withKibana } from '@kbn/kibana-react-plugin/public'; import { XJson } from '@kbn/es-ui-shared-plugin/public'; import { DATAFEED_STATE, JOB_STATE } from '../../../../../../common/constants/states'; import { CustomUrlsWrapper, isValidCustomUrls } from '../../../../components/custom_urls'; @@ -42,8 +42,8 @@ const { collapseLiteralStrings } = XJson; export class EditJobFlyoutUI extends Component { _initialJobFormState = null; - constructor(props) { - super(props); + constructor(props, constructorContext) { + super(props, constructorContext); this.state = { job: {}, @@ -120,7 +120,7 @@ export class EditJobFlyoutUI extends Component { showFlyout = (jobLite) => { const hasDatafeed = jobLite.hasDatafeed; - loadFullJob(jobLite.id) + loadFullJob(this.props.kibana.services.mlServices.mlApiServices, jobLite.id) .then((job) => { this.extractJob(job, hasDatafeed); this.setState({ diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/detectors.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/detectors.js index 14df6ccb8d8f457..23f35e872e7a80e 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/detectors.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/tabs/detectors.js @@ -11,12 +11,20 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiFieldText, EuiForm, EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui'; -import { mlJobService } from '../../../../../services/job_service'; +import { mlJobServiceFactory } from '../../../../../services/job_service'; +import { toastNotificationServiceProvider } from '../../../../../services/toast_notification_service'; import { detectorToString } from '../../../../../util/string_utils'; export class Detectors extends Component { - constructor(props) { - super(props); + static contextType = context; + + constructor(props, constructorContext) { + super(props, constructorContext); + + const mlJobService = mlJobServiceFactory( + toastNotificationServiceProvider(constructorContext.services.notifications.toasts), + constructorContext.services.mlServices.mlApiServices + ); this.detectors = mlJobService.getJobGroups().map((g) => ({ label: g.id })); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js index 4c6048292f692d1..638f27031f857b1 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js @@ -22,6 +22,7 @@ import { i18n } from '@kbn/i18n'; import { isManagedJob } from '../../../jobs_utils'; export function actionsMenuContent( + toastNotifications, application, mlJobService, showEditJobFlyout, @@ -112,7 +113,7 @@ export function actionsMenuContent( if (isManagedJob(item)) { showCloseJobsConfirmModal([item]); } else { - closeJobs([item], refreshJobs); + closeJobs(toastNotifications, mlJobService, [item], refreshJobs); } closeMenu(true); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js index 0bc90acc54ddc04..efb9211e99c0e0a 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js @@ -147,7 +147,7 @@ export class JobsListViewUI extends Component { } this.setState({ itemIdToExpandedRowMap }, () => { - loadFullJob(jobId) + loadFullJob(this.props.kibana.services.mlServices.mlApiServices, jobId) .then((job) => { const fullJobsList = { ...this.state.fullJobsList }; if (this.props.showNodeInfo === false) { diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/actions_menu.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/actions_menu.js index 73757a0091d5eda..963c19653799270 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/actions_menu.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/actions_menu.js @@ -12,6 +12,14 @@ import React, { Component } from 'react'; import { EuiButtonIcon, EuiContextMenuPanel, EuiContextMenuItem, EuiPopover } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { isManagedJob } from '../../../jobs_utils'; + +import { mlJobServiceFactory } from '../../../../services/job_service'; +import { toastNotificationServiceProvider } from '../../../../services/toast_notification_service'; + import { closeJobs, stopDatafeeds, @@ -20,13 +28,12 @@ import { isClosable, isResettable, } from '../utils'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { isManagedJob } from '../../../jobs_utils'; class MultiJobActionsMenuUI extends Component { - constructor(props) { - super(props); + static contextType = context; + + constructor(props, constructorContext) { + super(props, constructorContext); this.state = { isOpen: false, @@ -37,6 +44,13 @@ class MultiJobActionsMenuUI extends Component { this.canCloseJob = checkPermission('canCloseJob') && mlNodesAvailable(); this.canResetJob = checkPermission('canResetJob') && mlNodesAvailable(); this.canCreateMlAlerts = checkPermission('canCreateMlAlerts'); + + this.toastNoticiations = constructorContext.services.notifications.toasts; + const mlApiServices = constructorContext.services.mlServices.mlApiServices; + const toastNotificationService = toastNotificationServiceProvider( + constructorContext.services.notifications.toasts + ); + this.mlJobService = mlJobServiceFactory(toastNotificationService, mlApiServices); } onButtonClick = () => { @@ -101,7 +115,7 @@ class MultiJobActionsMenuUI extends Component { if (this.props.jobs.some((j) => isManagedJob(j))) { this.props.showCloseJobsConfirmModal(this.props.jobs); } else { - closeJobs(this.props.jobs); + closeJobs(this.toastNotifications, this.mlJobService, this.props.jobs); } this.closePopover(); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/group_selector/group_selector.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/group_selector/group_selector.js index 56aa2206f7c1a3b..50a30671a9ce869 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/group_selector/group_selector.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/group_selector/group_selector.js @@ -28,7 +28,7 @@ import { cloneDeep } from 'lodash'; import { checkPermission } from '../../../../../capabilities/check_capabilities'; import { GroupList } from './group_list'; import { NewGroupInput } from './new_group_input'; -import { getToastNotificationService } from '../../../../../services/toast_notification_service'; +import { toastNotificationServiceProvider } from '../../../../../services/toast_notification_service'; function createSelectedGroups(jobs, groups) { const jobIds = jobs.map((j) => j.id); @@ -61,8 +61,8 @@ export class GroupSelectorUI extends Component { refreshJobs: PropTypes.func.isRequired, }; - constructor(props) { - super(props); + constructor(props, constructorContext) { + super(props, constructorContext); this.state = { isPopoverOpen: false, @@ -73,6 +73,9 @@ export class GroupSelectorUI extends Component { this.refreshJobs = this.props.refreshJobs; this.canUpdateJob = checkPermission('canUpdateJob'); + this.toastNotificationsService = toastNotificationServiceProvider( + props.kibana.services.notifications.toasts + ); } static getDerivedStateFromProps(props, state) { @@ -134,6 +137,7 @@ export class GroupSelectorUI extends Component { }; applyChanges = () => { + const toastNotificationsService = this.toastNotificationsService; const { selectedGroups } = this.state; const { jobs } = this.props; const newJobs = jobs.map((j) => ({ @@ -163,7 +167,7 @@ export class GroupSelectorUI extends Component { // check success of each job update if (resp.hasOwnProperty(jobId)) { if (resp[jobId].success === false) { - getToastNotificationService().displayErrorToast(resp[jobId].error); + toastNotificationsService.displayErrorToast(resp[jobId].error); success = false; } } @@ -178,7 +182,7 @@ export class GroupSelectorUI extends Component { } }) .catch((error) => { - getToastNotificationService().displayErrorToast(error); + toastNotificationsService.displayErrorToast(error); console.error(error); }); }; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx index 69798c9f97b2137..1658c428d9b0095 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx @@ -25,6 +25,7 @@ import { i18n } from '@kbn/i18n'; import { resetJobs } from '../utils'; import type { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; import { RESETTING_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list'; +import { useMlKibana } from '../../../../contexts/kibana'; import { useMlJobService } from '../../../../services/job_service'; import { OpenJobsWarningCallout } from './open_jobs_warning_callout'; import { isManagedJob } from '../../../jobs_utils'; @@ -39,6 +40,11 @@ interface Props { } export const ResetJobModal: FC = ({ setShowFunction, unsetShowFunction, refreshJobs }) => { + const { + services: { + notifications: { toasts }, + }, + } = useMlKibana(); const mlJobService = useMlJobService(); const [resetting, setResetting] = useState(false); const [modalVisible, setModalVisible] = useState(false); @@ -75,7 +81,7 @@ export const ResetJobModal: FC = ({ setShowFunction, unsetShowFunction, r const resetJob = useCallback(async () => { setResetting(true); - await resetJobs(mlJobService, jobIds, deleteUserAnnotations); + await resetJobs(toasts, mlJobService, jobIds, deleteUserAnnotations); closeModal(); setTimeout(() => { refreshJobs(); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js index c4c53b00591f4d9..d56fc973a024929 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/start_datafeed_modal.js @@ -7,6 +7,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import moment from 'moment'; import { EuiButton, @@ -20,18 +21,23 @@ import { EuiCheckbox, } from '@elastic/eui'; -import moment from 'moment'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { context } from '@kbn/kibana-react-plugin/public'; + +import { mlJobServiceFactory } from '../../../../services/job_service'; +import { toastNotificationServiceProvider } from '../../../../services/toast_notification_service'; + +import { isManagedJob } from '../../../jobs_utils'; import { forceStartDatafeeds } from '../utils'; import { TimeRangeSelector } from './time_range_selector'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { isManagedJob } from '../../../jobs_utils'; - export class StartDatafeedModal extends Component { - constructor(props) { - super(props); + static contextType = context; + + constructor(props, constructorContext) { + super(props, constructorContext); const now = moment(); this.state = { @@ -50,6 +56,11 @@ export class StartDatafeedModal extends Component { this.initialSpecifiedStartTime = now; this.refreshJobs = this.props.refreshJobs; this.getShowCreateAlertFlyoutFunction = this.props.getShowCreateAlertFlyoutFunction; + this.toastNotifications = constructorContext.services.notifications.toasts; + this.mlJobService = mlJobServiceFactory( + toastNotificationServiceProvider(this.toastNotifications), + constructorContext.services.mlServices.mlApiServices + ); } componentDidMount() { @@ -114,7 +125,7 @@ export class StartDatafeedModal extends Component { ? this.state.endTime.valueOf() : this.state.endTime; - forceStartDatafeeds(jobs, start, end, () => { + forceStartDatafeeds(this.toastNotifications, this.mlJobService, jobs, start, end, () => { if (this.state.createAlert && jobs.length > 0) { this.getShowCreateAlertFlyoutFunction()(jobs.map((job) => job.id)); } diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts index f79e3938cb84762..6fd9a18cfe4eb0e 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.d.ts @@ -5,33 +5,77 @@ * 2.0. */ -import type { CombinedJobWithStats } from '../../../../../common/types/anomaly_detection_jobs'; +import type { ApplicationStart, ToastsStart } from '@kbn/core/public'; + +import type { DATAFEED_STATE } from '../../../../../common/constants/states'; +import type { + CombinedJobWithStats, + MlSummaryJob, +} from '../../../../../common/types/anomaly_detection_jobs'; import type { MlJobService } from '../../../services/job_service'; +import type { MlApiServices } from '../../../services/ml_api_service'; +export function loadFullJob( + mlApiServices: MlApiServices, + jobId: string +): Promise; +export function loadJobForCloning(mlApiServices: MlApiServices, jobId: string): Promise; +export function isStartable(jobs: CombinedJobWithStats[]): boolean; +export function isClosable(jobs: CombinedJobWithStats[]): boolean; +export function isResettable(jobs: CombinedJobWithStats[]): boolean; +export function forceStartDatafeeds( + toastNotifications: ToastsStart, + mlJobService: MlJobService, + jobs: CombinedJobWithStats[], + finish?: () => void +): Promise; export function stopDatafeeds( + toastNotifications: ToastsStart, mlJobService: MlJobService, - jobs: Array<{ id: string }>, - callback?: () => void + jobs: CombinedJobWithStats[] | MlSummaryJob[], + finish?: () => void +): Promise; +export function showResults( + toastNotifications: ToastsStart, + resp: any, + action: DATAFEED_STATE +): void; +export function cloneJob( + toastNotifications: ToastsStart, + application: ApplicationStart, + mlApiServices: MlApiServices, + mlJobService: MlJobService, + jobId: string ): Promise; export function closeJobs( + toastNotifications: ToastsStart, mlJobService: MlJobService, - jobs: Array<{ id: string }>, - callback?: () => void + jobs: CombinedJobWithStats[] | MlSummaryJob[], + finish?: () => void ): Promise; export function deleteJobs( + toastNotifications: ToastsStart, mlJobService: MlJobService, jobs: Array<{ id: string }>, deleteUserAnnotations?: boolean, deleteAlertingRules?: boolean, - callback?: () => void + finish?: () => void ): Promise; export function resetJobs( + toastNotifications: ToastsStart, mlJobService: MlJobService, jobIds: string[], deleteUserAnnotations?: boolean, - callback?: () => void + finish?: () => void ): Promise; -export function loadFullJob( - mlJobService: MlJobService, - jobId: string -): Promise; +export function filterJobs( + jobs: CombinedJobWithStats[], + clauses: Array<{ field: string; match: string; type: string; value: any }> +): CombinedJobWithStats[]; +export function jobProperty(job: CombinedJobWithStats, prop: string): any; +export function jobTagFilter(jobs: CombinedJobWithStats[], value: string): CombinedJobWithStats[]; +export function checkForAutoStartDatafeed( + mlJobService: MlJobService +): + | { id: string; hasDatafeed: boolean; latestTimestampSortValue: number; datafeedId: string } + | undefined; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js index 4a4a5bfcbbbaa01..c6cb3ab5bdf653f 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js @@ -8,11 +8,7 @@ import { each } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - getToastNotificationService, - toastNotificationServiceProvider, -} from '../../../services/toast_notification_service'; -import { getToastNotifications } from '../../../util/dependency_cache'; +import { toastNotificationServiceProvider } from '../../../services/toast_notification_service'; import { stringMatch } from '../../../util/string_utils'; import { JOB_STATE, DATAFEED_STATE } from '../../../../../common/constants/states'; import { JOB_ACTION } from '../../../../../common/constants/job_actions'; @@ -84,7 +80,14 @@ export function isResettable(jobs) { ); } -export function forceStartDatafeeds(mlJobService, jobs, start, end, finish = () => {}) { +export function forceStartDatafeeds( + toastNotifications, + mlJobService, + jobs, + start, + end, + finish = () => {} +) { const datafeedIds = jobs.filter((j) => j.hasDatafeed).map((j) => j.datafeedId); mlJobService .forceStartDatafeeds(datafeedIds, start, end) @@ -93,7 +96,6 @@ export function forceStartDatafeeds(mlJobService, jobs, start, end, finish = () finish(); }) .catch((error) => { - const toastNotifications = getToastNotifications(); toastNotifications.addDanger( i18n.translate('xpack.ml.jobsList.startJobErrorMessage', { defaultMessage: 'Jobs failed to start', @@ -104,7 +106,7 @@ export function forceStartDatafeeds(mlJobService, jobs, start, end, finish = () }); } -export function stopDatafeeds(mlJobService, jobs, finish = () => {}) { +export function stopDatafeeds(toastNotifications, mlJobService, jobs, finish = () => {}) { const datafeedIds = jobs.filter((j) => j.hasDatafeed).map((j) => j.datafeedId); mlJobService .stopDatafeeds(datafeedIds) @@ -113,7 +115,6 @@ export function stopDatafeeds(mlJobService, jobs, finish = () => {}) { finish(); }) .catch((error) => { - const toastNotifications = getToastNotifications(); toastNotifications.addDanger( i18n.translate('xpack.ml.jobsList.stopJobErrorMessage', { defaultMessage: 'Jobs failed to stop', @@ -124,7 +125,7 @@ export function stopDatafeeds(mlJobService, jobs, finish = () => {}) { }); } -function showResults(resp, action) { +function showResults(toastNotifications, resp, action) { const successes = []; const failures = []; for (const d in resp) { @@ -182,7 +183,6 @@ function showResults(resp, action) { }); } - const toastNotifications = getToastNotifications(); if (successes.length > 0) { toastNotifications.addSuccess( i18n.translate('xpack.ml.jobsList.actionExecuteSuccessfullyNotificationMessage', { @@ -214,11 +214,17 @@ function showResults(resp, action) { } } -export async function cloneJob(application, mlJobService, jobId) { +export async function cloneJob( + toastNotifications, + application, + mlApiServices, + mlJobService, + jobId +) { try { const [{ job: cloneableJob, datafeed }, originalJob] = await Promise.all([ - loadJobForCloning(jobId), - loadFullJob(jobId, false), + loadJobForCloning(mlApiServices, jobId), + loadFullJob(mlApiServices, jobId), ]); const createdBy = originalJob?.custom_settings?.created_by; @@ -277,7 +283,7 @@ export async function cloneJob(application, mlJobService, jobId) { application.navigateToApp(PLUGIN_ID, { path: ML_PAGES.ANOMALY_DETECTION_CREATE_JOB }); } catch (error) { - getToastNotificationService().displayErrorToast( + toastNotificationServiceProvider(toastNotifications).displayErrorToast( error, i18n.translate('xpack.ml.jobsList.cloneJobErrorMessage', { defaultMessage: 'Could not clone {jobId}. Job could not be found', @@ -287,7 +293,7 @@ export async function cloneJob(application, mlJobService, jobId) { } } -export function closeJobs(mlJobService, jobs, finish = () => {}) { +export function closeJobs(toastNotifications, mlJobService, jobs, finish = () => {}) { const jobIds = jobs.map((j) => j.id); mlJobService .closeJobs(jobIds) @@ -296,7 +302,7 @@ export function closeJobs(mlJobService, jobs, finish = () => {}) { finish(); }) .catch((error) => { - getToastNotificationService().displayErrorToast( + toastNotificationServiceProvider(toastNotifications).displayErrorToast( error, i18n.translate('xpack.ml.jobsList.closeJobErrorMessage', { defaultMessage: 'Jobs failed to close', @@ -306,7 +312,13 @@ export function closeJobs(mlJobService, jobs, finish = () => {}) { }); } -export function resetJobs(mlJobService, jobIds, deleteUserAnnotations, finish = () => {}) { +export function resetJobs( + toastNotifications, + mlJobService, + jobIds, + deleteUserAnnotations, + finish = () => {} +) { mlJobService .resetJobs(jobIds, deleteUserAnnotations) .then((resp) => { @@ -314,7 +326,7 @@ export function resetJobs(mlJobService, jobIds, deleteUserAnnotations, finish = finish(); }) .catch((error) => { - getToastNotificationService().displayErrorToast( + toastNotificationServiceProvider(toastNotifications).displayErrorToast( error, i18n.translate('xpack.ml.jobsList.resetJobErrorMessage', { defaultMessage: 'Jobs failed to reset', @@ -325,6 +337,7 @@ export function resetJobs(mlJobService, jobIds, deleteUserAnnotations, finish = } export function deleteJobs( + toastNotifications, mlJobService, jobs, deleteUserAnnotations, @@ -339,7 +352,7 @@ export function deleteJobs( finish(); }) .catch((error) => { - getToastNotificationService().displayErrorToast( + toastNotificationServiceProvider(toastNotifications).displayErrorToast( error, i18n.translate('xpack.ml.jobsList.deleteJobErrorMessage', { defaultMessage: 'Jobs failed to delete', diff --git a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx index 6da953ddb7ce491..fa1753a4342fcd9 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer/state_manager.tsx @@ -265,7 +265,7 @@ export const TimeSeriesExplorerUrlStateManager: FC diff --git a/x-pack/plugins/ml/public/application/services/job_service.js b/x-pack/plugins/ml/public/application/services/job_service.js index 1528d72cb267113..ff0b23524a8b239 100644 --- a/x-pack/plugins/ml/public/application/services/job_service.js +++ b/x-pack/plugins/ml/public/application/services/job_service.js @@ -112,7 +112,7 @@ class JobService { function error(err) { console.log('jobService error getting list of jobs:', err); - this.getToastNotificationService().displayErrorToast(err); + this.toastNotificationService.displayErrorToast(err); reject({ jobs, err }); } }); @@ -195,7 +195,7 @@ class JobService { function error(err) { console.log('JobService error getting list of jobs:', err); - this.getToastNotificationService().displayErrorToast(err); + this.toastNotificationService.displayErrorToast(err); reject({ jobs, err }); } }); @@ -235,7 +235,7 @@ class JobService { function error(err) { console.log('loadDatafeeds error getting list of datafeeds:', err); - this.getToastNotificationService().displayErrorToast(err); + this.toastNotificationService.displayErrorToast(err); reject({ jobs, err }); } }); diff --git a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js index 8540d6c803b7897..e842c0c3c1661aa 100644 --- a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js +++ b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_list_modal.js @@ -9,6 +9,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { context } from '@kbn/kibana-react-plugin/public'; import { EuiButton, EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; @@ -18,6 +19,8 @@ import { deleteFilterLists } from './delete_filter_lists'; * React modal for confirming deletion of filter lists. */ export class DeleteFilterListModal extends Component { + static contextType = context; + static displayName = 'DeleteFilterListModal'; static propTypes = { selectedFilterLists: PropTypes.array, @@ -46,7 +49,7 @@ export class DeleteFilterListModal extends Component { async doDelete() { const { selectedFilterLists, refreshFilterLists } = this.props; - await deleteFilterLists(selectedFilterLists); + await deleteFilterLists(this.context.services.notifications.toasts, selectedFilterLists); refreshFilterLists(); this.closeModal(); diff --git a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_lists.js b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_lists.js index 41dfc476d62e747..6334442a8e14f31 100644 --- a/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_lists.js +++ b/x-pack/plugins/ml/public/application/settings/filter_lists/components/delete_filter_list_modal/delete_filter_lists.js @@ -5,16 +5,13 @@ * 2.0. */ -import { getToastNotifications } from '../../../../util/dependency_cache'; import { i18n } from '@kbn/i18n'; -export async function deleteFilterLists(mlApiServices, filterListsToDelete) { +export async function deleteFilterLists(toastNotifications, mlApiServices, filterListsToDelete) { if (filterListsToDelete === undefined || filterListsToDelete.length === 0) { return; } - const toastNotifications = getToastNotifications(); - // Delete each of the specified filter lists in turn, waiting for each response // before deleting the next to minimize load on the cluster. toastNotifications.add( diff --git a/x-pack/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.js b/x-pack/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.js index 4c79b9128374380..bee8addc46e5be0 100644 --- a/x-pack/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.js +++ b/x-pack/plugins/ml/public/application/settings/filter_lists/edit/edit_filter_list.js @@ -285,7 +285,13 @@ export class EditFilterListUI extends Component { const { loadedFilter, newFilterId, description, items } = this.state; const filterId = this.props.filterId !== undefined ? this.props.filterId : newFilterId; - saveFilterList(filterId, description, items, loadedFilter) + saveFilterList( + this.props.kibana.services.notifications.toasts, + filterId, + description, + items, + loadedFilter + ) .then((savedFilter) => { this.setLoadedFilterState(savedFilter); this.returnToFiltersList(); diff --git a/x-pack/plugins/ml/public/application/settings/filter_lists/edit/utils.js b/x-pack/plugins/ml/public/application/settings/filter_lists/edit/utils.js index 491d347ab7d3cf9..ff4cc24e1a3423d 100644 --- a/x-pack/plugins/ml/public/application/settings/filter_lists/edit/utils.js +++ b/x-pack/plugins/ml/public/application/settings/filter_lists/edit/utils.js @@ -6,7 +6,6 @@ */ import { i18n } from '@kbn/i18n'; -import { getToastNotifications } from '../../../util/dependency_cache'; import { isJobIdValid } from '../../../../../common/util/job_utils'; export function isValidFilterListId(id) { @@ -16,11 +15,11 @@ export function isValidFilterListId(id) { // Saves a filter list, running an update if the supplied loadedFilterList, holding the // original filter list to which edits are being applied, is defined with a filter_id property. -export function saveFilterList(filterId, description, items, loadedFilterList) { +export function saveFilterList(toastNotifications, filterId, description, items, loadedFilterList) { return new Promise((resolve, reject) => { if (loadedFilterList === undefined || loadedFilterList.filter_id === undefined) { // Create a new filter. - addFilterList(filterId, description, items) + addFilterList(toastNotifications, filterId, description, items) .then((newFilter) => { resolve(newFilter); }) @@ -40,7 +39,7 @@ export function saveFilterList(filterId, description, items, loadedFilterList) { }); } -export function addFilterList(mlApiServices, filterId, description, items) { +export function addFilterList(toastNotifications, mlApiServices, filterId, description, items) { const filterWithIdExistsErrorMessage = i18n.translate( 'xpack.ml.settings.filterLists.filterWithIdExistsErrorMessage', { @@ -68,7 +67,6 @@ export function addFilterList(mlApiServices, filterId, description, items) { reject(error); }); } else { - const toastNotifications = getToastNotifications(); toastNotifications.addDanger(filterWithIdExistsErrorMessage); reject(new Error(filterWithIdExistsErrorMessage)); } diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts index ec201d29cdc3af9..90dfe2494619546 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.d.ts @@ -9,20 +9,21 @@ import React from 'react'; import type { TimeRangeBounds } from '@kbn/ml-time-buckets'; -interface Props { +interface TimeSeriesExplorerProps { appStateHandler: (action: string, payload: any) => void; autoZoomDuration: number | undefined; bounds: TimeRangeBounds | undefined; - dateFormatTz: string; lastRefresh: number; - selectedJobId: string | undefined; - selectedDetectorIndex: number; - selectedEntities: Record | undefined; + previousRefresh?: number; + dateFormatTz: string; + selectedJobId: string; + selectedDetectorIndex?: number; + selectedEntities?: Record; selectedForecastId?: string; - tableInterval: string; - tableSeverity: number; + tableInterval?: string; + tableSeverity?: number; zoom?: { from?: string; to?: string }; } // eslint-disable-next-line react/prefer-stateless-function -declare class TimeSeriesExplorer extends React.Component {} +declare class TimeSeriesExplorer extends React.Component {} diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 856d173311f09f8..e27d3b11083dba1 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -107,7 +107,7 @@ export class TimeSeriesExplorer extends React.Component { bounds: PropTypes.object.isRequired, dateFormatTz: PropTypes.string.isRequired, lastRefresh: PropTypes.number.isRequired, - previousRefresh: PropTypes.number.isRequired, + previousRefresh: PropTypes.number, selectedJobId: PropTypes.string.isRequired, selectedDetectorIndex: PropTypes.number, selectedEntities: PropTypes.object, diff --git a/x-pack/plugins/ml/public/application/util/time_series_explorer_service.ts b/x-pack/plugins/ml/public/application/util/time_series_explorer_service.ts index d4f2c974717e341..05763f62d082cf8 100644 --- a/x-pack/plugins/ml/public/application/util/time_series_explorer_service.ts +++ b/x-pack/plugins/ml/public/application/util/time_series_explorer_service.ts @@ -40,14 +40,14 @@ export interface Interval { expression: string; } -interface ChartDataPoint { +export interface ChartDataPoint { date: Date; value: number | null; upper?: number | null; lower?: number | null; } -interface FocusData { +export interface FocusData { focusChartData: ChartDataPoint[]; anomalyRecords: MlAnomalyRecordDoc[]; scheduledEvents: any;