From 3fb8c08929d8209b880f27b05db556e6a21c195b Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Tue, 3 Nov 2020 15:30:38 -0600 Subject: [PATCH] [ML] Fix toast notif show if no annotation data --- .../timeseries_chart_with_tooltip.tsx | 54 ++++++++++++++---- .../timeseriesexplorer/timeseriesexplorer.js | 55 +------------------ 2 files changed, 44 insertions(+), 65 deletions(-) diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx index cdd9d6ffb5142..89e7d292dbdf2 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/timeseries_chart/timeseries_chart_with_tooltip.tsx @@ -9,35 +9,46 @@ import { i18n } from '@kbn/i18n'; import { MlTooltipComponent } from '../../../components/chart_tooltip'; import { TimeseriesChart } from './timeseries_chart'; import { CombinedJob } from '../../../../../common/types/anomaly_detection_jobs'; -import { ml } from '../../../services/ml_api_service'; import { ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE } from '../../../../../common/constants/search'; import { extractErrorMessage } from '../../../../../common/util/errors'; import { Annotation } from '../../../../../common/types/annotations'; -import { useNotifications } from '../../../contexts/kibana'; +import { useMlKibana, useNotifications } from '../../../contexts/kibana'; +import { getBoundsRoundedToInterval } from '../../../util/time_buckets'; +import { ANNOTATION_EVENT_USER } from '../../../../../common/constants/annotations'; +import { getControlsForDetector } from '../../get_controls_for_detector'; interface TimeSeriesChartWithTooltipsProps { bounds: any; - selectedDetectorIndex: number; + detectorIndex: number; renderFocusChartOnly: boolean; selectedJob: CombinedJob; + selectedEntities: Record; showAnnotations: boolean; showForecast: boolean; showModelBounds: boolean; chartProps: any; lastRefresh: number; + contextAggregationInterval: any; } export const TimeSeriesChartWithTooltips: FC = ({ bounds, - selectedDetectorIndex, + detectorIndex, renderFocusChartOnly, selectedJob, + selectedEntities, showAnnotations, showForecast, showModelBounds, chartProps, lastRefresh, + contextAggregationInterval, }) => { const { toasts: toastNotifications } = useNotifications(); + const { + services: { + mlServices: { mlApiServices }, + }, + } = useMlKibana(); const [annotationData, setAnnotationData] = useState([]); @@ -55,6 +66,12 @@ export const TimeSeriesChartWithTooltips: FC = useEffect(() => { let unmounted = false; + const entities = getControlsForDetector(detectorIndex, selectedEntities, selectedJob.job_id); + const nonBlankEntities = Array.isArray(entities) + ? entities.filter((entity) => entity.fieldValue !== null) + : undefined; + const searchBounds = getBoundsRoundedToInterval(bounds, contextAggregationInterval, false); + /** * Loads the full list of annotations for job without any aggs or time boundaries * used to indicate existence of annotations that are beyond the selected time @@ -62,17 +79,23 @@ export const TimeSeriesChartWithTooltips: FC = */ const loadAnnotations = async (jobId: string) => { try { - const resp = await ml.annotations.getAnnotations({ + const resp = await mlApiServices.annotations.getAnnotations({ jobIds: [jobId], - earliestMs: null, - latestMs: null, + earliestMs: searchBounds.min.valueOf(), + latestMs: searchBounds.max.valueOf(), maxAnnotations: ANNOTATIONS_TABLE_DEFAULT_QUERY_SIZE, + fields: [ + { + field: 'event', + missing: ANNOTATION_EVENT_USER, + }, + ], + detectorIndex, + entities: nonBlankEntities, }); if (!unmounted) { if (Array.isArray(resp.annotations[jobId])) { setAnnotationData(resp.annotations[jobId]); - } else { - showAnnotationErrorToastNotification(); } } } catch (error) { @@ -83,9 +106,16 @@ export const TimeSeriesChartWithTooltips: FC = loadAnnotations(selectedJob.job_id); return () => { - unmounted = false; + unmounted = true; }; - }, [selectedJob.job_id, selectedDetectorIndex, lastRefresh]); + }, [ + selectedJob.job_id, + detectorIndex, + lastRefresh, + selectedEntities, + bounds, + contextAggregationInterval, + ]); return (
@@ -95,7 +125,7 @@ export const TimeSeriesChartWithTooltips: FC = {...chartProps} annotationData={annotationData} bounds={bounds} - detectorIndex={selectedDetectorIndex} + detectorIndex={detectorIndex} renderFocusChartOnly={renderFocusChartOnly} selectedJob={selectedJob} showAnnotations={showAnnotations} diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index b495e416a444c..720c1377d4035 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -378,59 +378,6 @@ export class TimeSeriesExplorer extends React.Component { ); }; - /** - * Loads available entity values. - * @param {Array} entities - Entity controls configuration - * @param {Object} searchTerm - Search term for partition, e.g. { partition_field: 'partition' } - */ - loadEntityValues = async (entities, searchTerm = {}) => { - this.setState({ entitiesLoading: true }); - - const { bounds, selectedJobId, selectedDetectorIndex } = this.props; - const selectedJob = mlJobService.getJob(selectedJobId); - - // Populate the entity input datalists with the values from the top records by score - // for the selected detector across the full time range. No need to pass through finish(). - const detectorIndex = selectedDetectorIndex; - - const { - partition_field: partitionField, - over_field: overField, - by_field: byField, - } = await mlResultsService - .fetchPartitionFieldsValues( - selectedJob.job_id, - searchTerm, - [ - { - fieldName: 'detector_index', - fieldValue: detectorIndex, - }, - ], - bounds.min.valueOf(), - bounds.max.valueOf() - ) - .toPromise(); - - const entityValues = {}; - entities.forEach((entity) => { - let fieldValues; - - if (partitionField?.name === entity.fieldName) { - fieldValues = partitionField.values; - } - if (overField?.name === entity.fieldName) { - fieldValues = overField.values; - } - if (byField?.name === entity.fieldName) { - fieldValues = byField.values; - } - entityValues[entity.fieldName] = fieldValues; - }); - - this.setState({ entitiesLoading: false, entityValues }); - }; - setForecastId = (forecastId) => { this.props.appStateHandler(APP_STATE_ACTION.SET_FORECAST_ID, forecastId); }; @@ -1188,10 +1135,12 @@ export class TimeSeriesExplorer extends React.Component {