From 5ccc5cb9cb240083dc659e1b5597652cd5dcd42c Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 14 Aug 2019 20:09:22 +0100 Subject: [PATCH] [ML] Adding bucket span estimator to new wizards (#43288) * [ML] Adding bucket span estimator to new wizards * disabling next button when estimating * fixing population --- .../common/job_creator/job_creator.ts | 8 +++ .../components/bucket_span/bucket_span.tsx | 31 ++++++-- .../bucket_span/bucket_span_input.tsx | 4 +- .../bucket_span_estimator.tsx | 28 ++++++++ .../estimate_bucket_span.ts | 70 +++++++++++++++++++ .../components/bucket_span_estimator/index.ts | 6 ++ .../components/multi_metric_view/settings.tsx | 2 +- .../components/population_view/settings.tsx | 2 +- .../single_metric_view/settings.tsx | 2 +- .../public/services/ml_api_service/index.d.ts | 4 ++ 10 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx create mode 100644 x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts create mode 100644 x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator.ts index 7416157e60c3e8..9c1e339c9bbe4c 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator.ts +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/common/job_creator/job_creator.ts @@ -95,11 +95,19 @@ export class JobCreator { return agg !== undefined ? agg : null; } + public get aggregations(): Aggregation[] { + return this._aggs; + } + public getField(index: number): Field | null { const field = this._fields[index]; return field !== undefined ? field : null; } + public get fields(): Field[] { + return this._fields; + } + public set bucketSpan(bucketSpan: BucketSpan) { this._job_config.analysis_config.bucket_span = bucketSpan; } diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx index eace905b2c6de4..dfe9272984b814 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span.tsx @@ -5,12 +5,18 @@ */ import React, { FC, useContext, useEffect, useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { BucketSpanInput } from './bucket_span_input'; import { JobCreatorContext } from '../../../job_creator_context'; import { Description } from './description'; +import { BucketSpanEstimator } from '../bucket_span_estimator'; -export const BucketSpan: FC = () => { +interface Props { + setIsValid: (proceed: boolean) => void; +} + +export const BucketSpan: FC = ({ setIsValid }) => { const { jobCreator, jobCreatorUpdate, @@ -20,6 +26,7 @@ export const BucketSpan: FC = () => { } = useContext(JobCreatorContext); const [bucketSpan, setBucketSpan] = useState(jobCreator.bucketSpan); const [validation, setValidation] = useState(jobValidator.bucketSpan); + const [estimating, setEstimating] = useState(false); useEffect(() => { jobCreator.bucketSpan = bucketSpan; @@ -34,13 +41,25 @@ export const BucketSpan: FC = () => { setValidation(jobValidator.bucketSpan); }, [jobValidatorUpdated]); + useEffect(() => { + setIsValid(estimating === false); + }, [estimating]); + return ( - + + + + + + + + ); }; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx index 4ad8cc05c4e8e7..7c1aaca9dc0c2d 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span/bucket_span_input.tsx @@ -11,11 +11,13 @@ interface Props { bucketSpan: string; setBucketSpan: (bs: string) => void; isInvalid: boolean; + disabled: boolean; } -export const BucketSpanInput: FC = ({ bucketSpan, setBucketSpan, isInvalid }) => { +export const BucketSpanInput: FC = ({ bucketSpan, setBucketSpan, isInvalid, disabled }) => { return ( setBucketSpan(e.target.value)} diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx new file mode 100644 index 00000000000000..a61d5c39f8294f --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/bucket_span_estimator.tsx @@ -0,0 +1,28 @@ +/* + * 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. + */ + +import React, { FC, useEffect } from 'react'; +import { EuiButton } from '@elastic/eui'; + +import { useEstimateBucketSpan, ESTIMATE_STATUS } from './estimate_bucket_span'; + +interface Props { + setEstimating(estimating: boolean): void; +} + +export const BucketSpanEstimator: FC = ({ setEstimating }) => { + const { status, estimateBucketSpan } = useEstimateBucketSpan(); + + useEffect(() => { + setEstimating(status === ESTIMATE_STATUS.RUNNING); + }, [status]); + + return ( + + Estimate bucket span + + ); +}; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts new file mode 100644 index 00000000000000..79b72121732e38 --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/estimate_bucket_span.ts @@ -0,0 +1,70 @@ +/* + * 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. + */ + +import { useContext, useState } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { toastNotifications } from 'ui/notify'; +import { JobCreatorContext } from '../../../job_creator_context'; +import { EVENT_RATE_FIELD_ID } from '../../../../../../../../common/types/fields'; +import { isMultiMetricJobCreator, isPopulationJobCreator } from '../../../../../common/job_creator'; +import { ml } from '../../../../../../../services/ml_api_service'; +import { useKibanaContext } from '../../../../../../../contexts/kibana'; + +export enum ESTIMATE_STATUS { + NOT_RUNNING, + RUNNING, +} + +export function useEstimateBucketSpan() { + const { jobCreator, jobCreatorUpdate } = useContext(JobCreatorContext); + const kibanaContext = useKibanaContext(); + + const [status, setStatus] = useState(ESTIMATE_STATUS.NOT_RUNNING); + + const data = { + aggTypes: jobCreator.aggregations.map(a => a.dslName), + duration: { + start: jobCreator.start, + end: jobCreator.end, + }, + fields: jobCreator.fields.map(f => (f.id === EVENT_RATE_FIELD_ID ? null : f.id)), + index: kibanaContext.currentIndexPattern.title, + query: kibanaContext.combinedQuery, + splitField: + (isMultiMetricJobCreator(jobCreator) || isPopulationJobCreator(jobCreator)) && + jobCreator.splitField !== null + ? jobCreator.splitField.id + : undefined, + timeField: kibanaContext.currentIndexPattern.timeFieldName, + }; + + async function estimateBucketSpan() { + setStatus(ESTIMATE_STATUS.RUNNING); + const { name, error, message } = await ml.estimateBucketSpan(data); + setStatus(ESTIMATE_STATUS.NOT_RUNNING); + if (error === true) { + let text = ''; + if (message !== undefined) { + if (typeof message === 'object') { + text = message.msg || JSON.stringify(message); + } else { + text = message; + } + } + toastNotifications.addDanger({ + title: i18n.translate('xpack.ml.newJob.wizard.estimateBucketSpanError', { + defaultMessage: `Bucket span estimation error`, + }), + text, + }); + } else { + jobCreator.bucketSpan = name; + jobCreatorUpdate(); + } + } + return { status, estimateBucketSpan }; +} diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts new file mode 100644 index 00000000000000..45e0d10fd29a5e --- /dev/null +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/bucket_span_estimator/index.ts @@ -0,0 +1,6 @@ +/* + * 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 { BucketSpanEstimator } from './bucket_span_estimator'; diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx index 03cd9b2dee232c..8b3d718f880e97 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/multi_metric_view/settings.tsx @@ -45,7 +45,7 @@ export const MultiMetricSettings: FC = ({ isActive, setIsValid }) => { - + diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/settings.tsx index ee010f89c94a22..61d8a5f358964a 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/settings.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/population_view/settings.tsx @@ -36,7 +36,7 @@ export const PopulationSettings: FC = ({ isActive, setIsValid }) => { - + diff --git a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/settings.tsx b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/settings.tsx index 9d01494e59b723..1e6e137799d561 100644 --- a/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/settings.tsx +++ b/x-pack/legacy/plugins/ml/public/jobs/new_job_new/pages/components/pick_fields_step/components/single_metric_view/settings.tsx @@ -51,7 +51,7 @@ export const SingleMetricSettings: FC = ({ isActive, setIsValid }) => { - + diff --git a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts index 7433a38cc5e307..d2d40a9a54d31f 100644 --- a/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts +++ b/x-pack/legacy/plugins/ml/public/services/ml_api_service/index.d.ts @@ -121,6 +121,10 @@ declare interface Ml { end: number ): Promise<{ progress: number; isRunning: boolean }>; }; + + estimateBucketSpan( + data: object + ): Promise<{ name: string; ms: number; error?: boolean; message?: { msg: string } | string }>; } declare const ml: Ml;