Skip to content

Commit f18e84d

Browse files
[ML] DF Analytics results: ensure View link is only enabled when job has successfully completed (#73539)
* disable view link if job is incomplete or failed * ensure hooks run before return to avoid react error
1 parent 5b09dd9 commit f18e84d

File tree

3 files changed

+97
-26
lines changed

3 files changed

+97
-26
lines changed

x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
5656

5757
const { columnsWithCharts, errorMessage, status, tableItems } = outlierData;
5858

59+
/* eslint-disable-next-line react-hooks/rules-of-hooks */
60+
const colorRange = useColorRange(
61+
COLOR_RANGE.BLUE,
62+
COLOR_RANGE_SCALE.INFLUENCER,
63+
jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1
64+
);
65+
5966
// if it's a searchBar syntax error leave the table visible so they can try again
6067
if (status === INDEX_STATUS.ERROR && !errorMessage.includes('failed to create query')) {
6168
return (
@@ -74,13 +81,6 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
7481
);
7582
}
7683

77-
/* eslint-disable-next-line react-hooks/rules-of-hooks */
78-
const colorRange = useColorRange(
79-
COLOR_RANGE.BLUE,
80-
COLOR_RANGE_SCALE.INFLUENCER,
81-
jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1
82-
);
83-
8484
return (
8585
<EuiPanel data-test-subj="mlDFAnalyticsOutlierExplorationTablePanel">
8686
{jobConfig !== undefined && needsDestIndexPattern && (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { i18n } from '@kbn/i18n';
8+
import {
9+
isRegressionAnalysis,
10+
isOutlierAnalysis,
11+
isClassificationAnalysis,
12+
} from '../../../../common/analytics';
13+
import {
14+
DataFrameAnalyticsListRow,
15+
isDataFrameAnalyticsStopped,
16+
isDataFrameAnalyticsFailed,
17+
getDataFrameAnalyticsProgressPhase,
18+
} from '../analytics_list/common';
19+
20+
const unknownJobTypeMessage = i18n.translate(
21+
'xpack.ml.dataframe.analyticsList.viewActionUnknownJobTypeToolTipContent',
22+
{
23+
defaultMessage: 'There is no results page available for this type of data frame analytics job.',
24+
}
25+
);
26+
const jobNotStartedMessage = i18n.translate(
27+
'xpack.ml.dataframe.analyticsList.viewActionJobNotStartedToolTipContent',
28+
{
29+
defaultMessage:
30+
'The data frame analytics job did not start. There is no results page available.',
31+
}
32+
);
33+
const jobNotFinishedMessage = i18n.translate(
34+
'xpack.ml.dataframe.analyticsList.viewActionJobNotFinishedToolTipContent',
35+
{
36+
defaultMessage:
37+
'The data frame analytics job is not finished. There is no results page available.',
38+
}
39+
);
40+
const jobFailedMessage = i18n.translate(
41+
'xpack.ml.dataframe.analyticsList.viewActionJobFailedToolTipContent',
42+
{
43+
defaultMessage: 'The data frame analytics job failed. There is no results page available.',
44+
}
45+
);
46+
47+
interface ViewLinkStatusReturn {
48+
disabled: boolean;
49+
tooltipContent?: string;
50+
}
51+
52+
export function getViewLinkStatus(item: DataFrameAnalyticsListRow): ViewLinkStatusReturn {
53+
const viewLinkStatus: ViewLinkStatusReturn = { disabled: false };
54+
55+
const progressStats = getDataFrameAnalyticsProgressPhase(item.stats);
56+
const jobFailed = isDataFrameAnalyticsFailed(item.stats.state);
57+
const jobNotStarted = progressStats.currentPhase === 1 && progressStats.progress === 0;
58+
const jobFinished =
59+
isDataFrameAnalyticsStopped(item.stats.state) &&
60+
progressStats.currentPhase === progressStats.totalPhases &&
61+
progressStats.progress === 100;
62+
const isUnknownJobType =
63+
!isRegressionAnalysis(item.config.analysis) &&
64+
!isOutlierAnalysis(item.config.analysis) &&
65+
!isClassificationAnalysis(item.config.analysis);
66+
67+
const disabled = !jobFinished || jobFailed || isUnknownJobType;
68+
69+
if (disabled) {
70+
viewLinkStatus.disabled = true;
71+
if (isUnknownJobType) {
72+
viewLinkStatus.tooltipContent = unknownJobTypeMessage;
73+
} else if (jobFailed) {
74+
viewLinkStatus.tooltipContent = jobFailedMessage;
75+
} else if (jobNotStarted) {
76+
viewLinkStatus.tooltipContent = jobNotStartedMessage;
77+
} else if (!jobFinished) {
78+
viewLinkStatus.tooltipContent = jobNotFinishedMessage;
79+
}
80+
}
81+
82+
return viewLinkStatus;
83+
}

x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_view/view_button.tsx

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ import React, { FC } from 'react';
88
import { i18n } from '@kbn/i18n';
99
import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
1010

11-
import {
12-
getAnalysisType,
13-
isRegressionAnalysis,
14-
isOutlierAnalysis,
15-
isClassificationAnalysis,
16-
} from '../../../../common/analytics';
11+
import { getAnalysisType } from '../../../../common/analytics';
1712
import { useMlKibana } from '../../../../../contexts/kibana';
1813

1914
import { getResultsUrl, DataFrameAnalyticsListRow } from '../analytics_list/common';
2015

16+
import { getViewLinkStatus } from './get_view_link_status';
17+
2118
interface ViewButtonProps {
2219
item: DataFrameAnalyticsListRow;
2320
isManagementTable: boolean;
@@ -30,11 +27,8 @@ export const ViewButton: FC<ViewButtonProps> = ({ item, isManagementTable }) =>
3027
},
3128
} = useMlKibana();
3229

30+
const { disabled, tooltipContent } = getViewLinkStatus(item);
3331
const analysisType = getAnalysisType(item.config.analysis);
34-
const buttonDisabled =
35-
!isRegressionAnalysis(item.config.analysis) &&
36-
!isOutlierAnalysis(item.config.analysis) &&
37-
!isClassificationAnalysis(item.config.analysis);
3832

3933
const url = getResultsUrl(item.id, analysisType);
4034
const navigator = isManagementTable
@@ -52,23 +46,17 @@ export const ViewButton: FC<ViewButtonProps> = ({ item, isManagementTable }) =>
5246
data-test-subj="mlAnalyticsJobViewButton"
5347
flush="left"
5448
iconType="visTable"
55-
isDisabled={buttonDisabled}
49+
isDisabled={disabled}
5650
onClick={navigator}
5751
size="s"
5852
>
5953
{buttonText}
6054
</EuiButtonEmpty>
6155
);
6256

63-
if (buttonDisabled) {
57+
if (disabled) {
6458
return (
65-
<EuiToolTip
66-
position="top"
67-
content={i18n.translate('xpack.ml.dataframe.analyticsList.viewActionToolTipContent', {
68-
defaultMessage:
69-
'There is no results page available for this type of data frame analytics job.',
70-
})}
71-
>
59+
<EuiToolTip position="top" content={tooltipContent}>
7260
{button}
7361
</EuiToolTip>
7462
);

0 commit comments

Comments
 (0)