[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:
parent
ba9aed4b4e
commit
94321ccdd0
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
Loading…
Reference in a new issue