[ML] DF Analytics Creation: add progress indicator (#69583)

* add progress indicator to creation wizard page

* only show progress bar if job is started immediately

* add title and switch to timeout

* fix progress check

* clean up interval on unmount

* fix types

* clear interval if stats undefined. show progress if job created
This commit is contained in:
Melissa Alvarez 2020-06-24 14:36:37 -04:00 committed by GitHub
parent ba9aed4b4e
commit 94321ccdd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 115 additions and 0 deletions

View file

@ -19,6 +19,7 @@ import { CreateAnalyticsFormProps } from '../../../analytics_management/hooks/us
import { Messages } from '../shared';
import { ANALYTICS_STEPS } from '../../page';
import { BackToListPanel } from '../back_to_list_panel';
import { ProgressStats } from './progress_stats';
interface Props extends CreateAnalyticsFormProps {
step: ANALYTICS_STEPS;
@ -27,8 +28,10 @@ interface Props extends CreateAnalyticsFormProps {
export const CreateStep: FC<Props> = ({ actions, state, step }) => {
const { createAnalyticsJob, startAnalyticsJob } = actions;
const { isAdvancedEditorValidJson, isJobCreated, isJobStarted, isValid, requestMessages } = state;
const { jobId } = state.form;
const [checked, setChecked] = useState<boolean>(true);
const [showProgress, setShowProgress] = useState<boolean>(false);
if (step !== ANALYTICS_STEPS.CREATE) return null;
@ -36,6 +39,7 @@ export const CreateStep: FC<Props> = ({ actions, state, step }) => {
await createAnalyticsJob();
if (checked) {
setShowProgress(true);
startAnalyticsJob();
}
};
@ -82,6 +86,7 @@ export const CreateStep: FC<Props> = ({ actions, state, step }) => {
)}
<EuiSpacer size="s" />
<Messages messages={requestMessages} />
{isJobCreated === true && showProgress && <ProgressStats jobId={jobId} />}
{isJobCreated === true && <BackToListPanel />}
</Fragment>
);

View file

@ -0,0 +1,110 @@
/*
* 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, useState, useEffect } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiProgress, EuiSpacer, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useMlKibana } from '../../../../../contexts/kibana';
import { getDataFrameAnalyticsProgressPhase } from '../../../analytics_management/components/analytics_list/common';
import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics';
import { ml } from '../../../../../services/ml_api_service';
import { DataFrameAnalyticsId } from '../../../../common/analytics';
export const PROGRESS_REFRESH_INTERVAL_MS = 1000;
export const ProgressStats: FC<{ jobId: DataFrameAnalyticsId }> = ({ jobId }) => {
const [initialized, setInitialized] = useState<boolean>(false);
const [currentProgress, setCurrentProgress] = useState<
| {
currentPhase: number;
progress: number;
totalPhases: number;
}
| undefined
>(undefined);
const {
services: { notifications },
} = useMlKibana();
useEffect(() => {
setInitialized(true);
}, []);
useEffect(() => {
const interval = setInterval(async () => {
try {
const analyticsStats = await ml.dataFrameAnalytics.getDataFrameAnalyticsStats(jobId);
const jobStats = isGetDataFrameAnalyticsStatsResponseOk(analyticsStats)
? analyticsStats.data_frame_analytics[0]
: undefined;
if (jobStats !== undefined) {
const progressStats = getDataFrameAnalyticsProgressPhase(jobStats);
setCurrentProgress(progressStats);
if (
progressStats.currentPhase === progressStats.totalPhases &&
progressStats.progress === 100
) {
clearInterval(interval);
}
} else {
clearInterval(interval);
}
} catch (e) {
notifications.toasts.addDanger(
i18n.translate('xpack.ml.dataframe.analytics.create.analyticsProgressErrorMessage', {
defaultMessage: 'An error occurred getting progress stats for analytics job {jobId}',
values: { jobId },
})
);
clearInterval(interval);
}
}, PROGRESS_REFRESH_INTERVAL_MS);
return () => clearInterval(interval);
}, [initialized]);
if (currentProgress === undefined) return null;
return (
<>
<EuiSpacer />
<EuiText size="m">
<strong>
{i18n.translate('xpack.ml.dataframe.analytics.create.analyticsProgressTitle', {
defaultMessage: 'Progress',
})}
</strong>
</EuiText>
<EuiSpacer size="s" />
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiText size="s">
<strong>
{i18n.translate('xpack.ml.dataframe.analytics.create.analyticsProgressPhaseTitle', {
defaultMessage: 'Phase',
})}{' '}
{currentProgress.currentPhase}/{currentProgress.totalPhases}
</strong>
</EuiText>
</EuiFlexItem>
<EuiFlexItem style={{ width: '400px' }} grow={false}>
<EuiProgress
value={currentProgress.progress}
max={100}
color="primary"
size="l"
data-test-subj="mlAnalyticsCreationWizardProgress"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s">{`${currentProgress.progress}%`}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</>
);
};