From 41552018659642508ce52909429c1cc2e63df5c1 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Tue, 1 Sep 2020 16:10:59 -0500 Subject: [PATCH] [ML] Change to pass 'invalid' to url to retain the original full range + update field values --- .../plugins/ml/common/constants/settings.ts | 4 +-- .../public/application/explorer/explorer.js | 11 +++++++- .../application/routing/routes/explorer.tsx | 26 ++++++------------- .../routing/routes/timeseriesexplorer.tsx | 25 +++++------------- .../application/services/job_service.js | 26 +++++++++++++------ .../timeseriesexplorer/timeseriesexplorer.js | 11 +++++++- .../ml/server/lib/register_settings.ts | 8 +++--- 7 files changed, 59 insertions(+), 52 deletions(-) diff --git a/x-pack/plugins/ml/common/constants/settings.ts b/x-pack/plugins/ml/common/constants/settings.ts index 55deb48652b0c..358089a97f0f5 100644 --- a/x-pack/plugins/ml/common/constants/settings.ts +++ b/x-pack/plugins/ml/common/constants/settings.ts @@ -5,5 +5,5 @@ */ export const FILE_DATA_VISUALIZER_MAX_FILE_SIZE = 'ml:fileDataVisualizerMaxFileSize'; -export const ANOMALY_DETECTION_ENABLE_TIME_RANGE = 'ml:anomalyDetectionDefaultTimeRangeEnable'; -export const ANOMALY_DETECTION_DEFAULT_TIME_RANGE = 'ml:anomalyDetectionDefaultTimeRangeSet'; +export const ANOMALY_DETECTION_ENABLE_TIME_RANGE = 'ml:anomalyDetectionTimeDefaultsEnable'; +export const ANOMALY_DETECTION_DEFAULT_TIME_RANGE = 'ml:anomalyDetectionTimeDefaults'; diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js index 4329f898e9f1e..0fd181342fcf6 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer.js @@ -68,6 +68,7 @@ import { ExplorerChartsContainer } from './explorer_charts/explorer_charts_conta import { AnomaliesTable } from '../components/anomalies_table/anomalies_table'; import { getTimefilter, getToastNotifications } from '../util/dependency_cache'; +import { ANOMALY_DETECTION_DEFAULT_TIME_RANGE } from '../../../common/constants/settings'; const ExplorerPage = ({ children, @@ -149,7 +150,15 @@ export class Explorer extends React.Component { const { invalidTimeRangeError } = this.props; if (invalidTimeRangeError) { const toastNotifications = getToastNotifications(); - toastNotifications.addWarning(invalidTimeRangeError); + toastNotifications.addWarning( + i18n.translate('xpack.ml.explorer.invalidTimeRangeInUrlCallout', { + defaultMessage: + 'The time filter changed to the full range for this job due to invalid default time filter. Please check the advanced settings for {field}.', + values: { + field: ANOMALY_DETECTION_DEFAULT_TIME_RANGE, + }, + }) + ); } } diff --git a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx index 1c281cb941384..191933812ffe3 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx @@ -33,7 +33,7 @@ import { getBreadcrumbWithUrlForApp } from '../breadcrumbs'; import { useTimefilter } from '../../contexts/kibana'; import { isViewBySwimLaneData } from '../../explorer/swimlane_container'; import { JOB_ID } from '../../../../common/constants/anomalies'; -import { validateTimeRange } from '../../util/date_utils'; + export const explorerRouteFactory = (navigateToPath: NavigateToPath): MlRoute => ({ path: '/explorer', render: (props, deps) => , @@ -72,7 +72,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim const [globalState, setGlobalState] = useUrlState('_g'); const [lastRefresh, setLastRefresh] = useState(0); const [stoppedPartitions, setStoppedPartitions] = useState(); - const [invalidTimeRangeError, setInValidTimeRangeError] = useState(); + const [invalidTimeRangeError, setInValidTimeRangeError] = useState(false); const timefilter = useTimefilter({ timeRangeSelector: true, autoRefreshSelector: true }); const { jobIds } = useJobSelection(jobsWithTimeRange); @@ -98,23 +98,13 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim // `timefilter.getBounds()` to update `bounds` in this component's state. useEffect(() => { if (globalState?.time !== undefined) { - if (!validateTimeRange(globalState.time)) { - setInValidTimeRangeError( - i18n.translate('xpack.ml.explorer.invalidTimeRangeInUrlCallout', { - defaultMessage: - "The time filter changed to the full range for this job due to invalid default time filter from '{from}' to '{to}'. Please check the advanced settings.", - values: { - from: globalState.time.from, - to: globalState.time.to, - }, - }) - ); - } else { - timefilter.setTime({ - from: globalState.time.from, - to: globalState.time.to, - }); + if (globalState.time.mode === 'invalid') { + setInValidTimeRangeError(true); } + timefilter.setTime({ + from: globalState.time.from, + to: globalState.time.to, + }); const timefilterBounds = timefilter.getBounds(); // Only if both min/max bounds are valid moment times set the bounds. diff --git a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx index 9fd6cf2450f12..817c975415997 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx @@ -38,7 +38,6 @@ import { useResolver } from '../use_resolver'; import { basicResolvers } from '../resolvers'; import { getBreadcrumbWithUrlForApp } from '../breadcrumbs'; import { useTimefilter } from '../../contexts/kibana'; -import { validateTimeRange } from '../../..'; export const timeSeriesExplorerRouteFactory = (navigateToPath: NavigateToPath): MlRoute => ({ path: '/timeseriesexplorer', @@ -92,7 +91,7 @@ export const TimeSeriesExplorerUrlStateManager: FC(); const timefilter = useTimefilter({ timeRangeSelector: true, autoRefreshSelector: true }); - const [invalidTimeRangeError, setInValidTimeRangeError] = useState(); + const [invalidTimeRangeError, setInValidTimeRangeError] = useState(false); const refresh = useRefresh(); useEffect(() => { @@ -116,23 +115,13 @@ export const TimeSeriesExplorerUrlStateManager: FC(undefined); useEffect(() => { if (globalState?.time !== undefined) { - if (!validateTimeRange(globalState.time)) { - setInValidTimeRangeError( - i18n.translate('xpack.ml.timeSeriesExplorer.invalidTimeRangeInUrlCallout', { - defaultMessage: - "The time filter changed to the full range for this job due to invalid default time filter from '{from}' to '{to}'. Please check the advanced settings.", - values: { - from: globalState.time.from, - to: globalState.time.to, - }, - }) - ); - } else { - timefilter.setTime({ - from: globalState.time.from, - to: globalState.time.to, - }); + if (globalState.time.mode === 'invalid') { + setInValidTimeRangeError(true); } + timefilter.setTime({ + from: globalState.time.from, + to: globalState.time.to, + }); const timefilterBounds = timefilter.getBounds(); // Only if both min/max bounds are valid moment times set the bounds. 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 52b85edb06b7a..640f63617b7d4 100644 --- a/x-pack/plugins/ml/public/application/services/job_service.js +++ b/x-pack/plugins/ml/public/application/services/job_service.js @@ -21,7 +21,7 @@ import { ML_DATA_PREVIEW_COUNT } from '../../../common/util/job_utils'; import { TIME_FORMAT } from '../../../common/constants/time_format'; import { parseInterval } from '../../../common/util/parse_interval'; import { toastNotificationServiceProvider } from '../services/toast_notification_service'; - +import { validateTimeRange } from '../util/date_utils'; const msgs = mlMessageBarService; let jobs = []; let datafeedIds = {}; @@ -935,22 +935,29 @@ function createJobStats(jobsList, jobStats) { function createResultsUrlForJobs(jobsList, resultsPage, userTimeRange) { let from = undefined; let to = undefined; + let mode = 'absolute'; const jobIds = jobsList.map((j) => j.id); - // if user input is a valid time range object - if (userTimeRange) { + // if the custom default time filter is set and enabled in advanced settings + // if time is either absolute date or proper datemath format + if (validateTimeRange(userTimeRange)) { from = userTimeRange.from; to = userTimeRange.to; + // if both pass datemath's checks but are not technically absolute dates, use 'quick' + // e.g. "now-15m" "now+1d" const fromFieldAValidDate = moment(userTimeRange.from).isValid(); const toFieldAValidDate = moment(userTimeRange.to).isValid(); - // if both are not a valid date, use 'quick' - // e.g. "now-15m" "now+1d" if (!fromFieldAValidDate && !toFieldAValidDate) { return createResultsUrl(jobIds, from, to, resultsPage, 'quick'); } - // if both fields are absolute date - // continue to createResultsUrl with from and to converted as normal } else { + // if time range is specified but with incorrect format + // change back to the default time range but alert the user + // that the advanced setting config is invalid + if (userTimeRange) { + mode = 'invalid'; + } + if (jobsList.length === 1) { from = jobsList[0].earliestTimestampMs; to = jobsList[0].latestResultsTimestampMs; // Will be max(latest source data, latest bucket results) @@ -966,7 +973,7 @@ function createResultsUrlForJobs(jobsList, resultsPage, userTimeRange) { const fromString = moment(from).format(TIME_FORMAT); // Defaults to 'now' if 'from' is undefined const toString = moment(to).format(TIME_FORMAT); // Defaults to 'now' if 'to' is undefined - return createResultsUrl(jobIds, fromString, toString, resultsPage); + return createResultsUrl(jobIds, fromString, toString, resultsPage, mode); } function createResultsUrl(jobIds, start, end, resultsPage, mode = 'absolute') { @@ -991,6 +998,9 @@ function createResultsUrl(jobIds, start, end, resultsPage, mode = 'absolute') { path += `?_g=(ml:(jobIds:!(${idString}))`; path += `,refreshInterval:(display:Off,pause:!f,value:0),time:(from:'${from}'`; path += `,to:'${to}'`; + if (mode === 'invalid') { + path += `,mode:invalid`; + } path += "))&_a=(query:(query_string:(analyze_wildcard:!t,query:'*')))"; return path; diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index d290ea0f58ed7..228af93a2c17f 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -83,6 +83,7 @@ import { getFocusData, } from './timeseriesexplorer_utils'; import { EMPTY_FIELD_VALUE_LABEL } from './components/entity_control/entity_control'; +import { ANOMALY_DETECTION_DEFAULT_TIME_RANGE } from '../../../common/constants/settings'; // Used to indicate the chart is being plotted across // all partition field values, where the cardinality of the field cannot be @@ -838,7 +839,15 @@ export class TimeSeriesExplorer extends React.Component { const { invalidTimeRangeError } = this.props; if (invalidTimeRangeError) { const toastNotifications = getToastNotifications(); - toastNotifications.addWarning(invalidTimeRangeError); + toastNotifications.addWarning( + i18n.translate('xpack.ml.timeSeriesExplorer.invalidTimeRangeInUrlCallout', { + defaultMessage: + 'The time filter changed to the full range for this job due to invalid default time filter. Please check the advanced settings for {field}.', + values: { + field: ANOMALY_DETECTION_DEFAULT_TIME_RANGE, + }, + }) + ); } // Required to redraw the time series chart when the container is resized. diff --git a/x-pack/plugins/ml/server/lib/register_settings.ts b/x-pack/plugins/ml/server/lib/register_settings.ts index 2b18f17820ede..4843e55533a5a 100644 --- a/x-pack/plugins/ml/server/lib/register_settings.ts +++ b/x-pack/plugins/ml/server/lib/register_settings.ts @@ -36,14 +36,14 @@ export function registerKibanaSettings(coreSetup: CoreSetup) { }, [ANOMALY_DETECTION_ENABLE_TIME_RANGE]: { name: i18n.translate('xpack.ml.advancedSettings.enableAnomalyDetectionDefaultTimeRangeName', { - defaultMessage: 'Enable default time range for anomaly detection jobs.', + defaultMessage: 'Enable default time range for anomaly detection jobs', }), value: false, schema: schema.boolean(), description: i18n.translate( - 'xpack.ml.advancedSettings.anomalyDetectionDefaultTimeRangeDesc', + 'xpack.ml.advancedSettings.enableAnomalyDetectionDefaultTimeRangeDesc', { - defaultMessage: 'Use a default time range to view anomaly detection jobs.', + defaultMessage: 'Use a default time filter to view anomaly detection jobs.', } ), category: ['Machine Learning'], @@ -60,7 +60,7 @@ export function registerKibanaSettings(coreSetup: CoreSetup) { description: i18n.translate( 'xpack.ml.advancedSettings.anomalyDetectionDefaultTimeRangeDesc', { - defaultMessage: 'The default time range to view anomaly detection jobs.', + defaultMessage: 'The default time filter to view anomaly detection jobs.', } ), schema: schema.object({