[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
This commit is contained in:
Melissa Alvarez 2020-07-29 11:19:53 -04:00 committed by GitHub
parent 4f8e7baa3e
commit 2dca40ab2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 26 deletions

View file

@ -56,6 +56,13 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
const { columnsWithCharts, errorMessage, status, tableItems } = outlierData;
/* eslint-disable-next-line react-hooks/rules-of-hooks */
const colorRange = useColorRange(
COLOR_RANGE.BLUE,
COLOR_RANGE_SCALE.INFLUENCER,
jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1
);
// if it's a searchBar syntax error leave the table visible so they can try again
if (status === INDEX_STATUS.ERROR && !errorMessage.includes('failed to create query')) {
return (
@ -74,13 +81,6 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
);
}
/* eslint-disable-next-line react-hooks/rules-of-hooks */
const colorRange = useColorRange(
COLOR_RANGE.BLUE,
COLOR_RANGE_SCALE.INFLUENCER,
jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1
);
return (
<EuiPanel data-test-subj="mlDFAnalyticsOutlierExplorationTablePanel">
{jobConfig !== undefined && needsDestIndexPattern && (

View file

@ -0,0 +1,83 @@
/*
* 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 { i18n } from '@kbn/i18n';
import {
isRegressionAnalysis,
isOutlierAnalysis,
isClassificationAnalysis,
} from '../../../../common/analytics';
import {
DataFrameAnalyticsListRow,
isDataFrameAnalyticsStopped,
isDataFrameAnalyticsFailed,
getDataFrameAnalyticsProgressPhase,
} from '../analytics_list/common';
const unknownJobTypeMessage = i18n.translate(
'xpack.ml.dataframe.analyticsList.viewActionUnknownJobTypeToolTipContent',
{
defaultMessage: 'There is no results page available for this type of data frame analytics job.',
}
);
const jobNotStartedMessage = i18n.translate(
'xpack.ml.dataframe.analyticsList.viewActionJobNotStartedToolTipContent',
{
defaultMessage:
'The data frame analytics job did not start. There is no results page available.',
}
);
const jobNotFinishedMessage = i18n.translate(
'xpack.ml.dataframe.analyticsList.viewActionJobNotFinishedToolTipContent',
{
defaultMessage:
'The data frame analytics job is not finished. There is no results page available.',
}
);
const jobFailedMessage = i18n.translate(
'xpack.ml.dataframe.analyticsList.viewActionJobFailedToolTipContent',
{
defaultMessage: 'The data frame analytics job failed. There is no results page available.',
}
);
interface ViewLinkStatusReturn {
disabled: boolean;
tooltipContent?: string;
}
export function getViewLinkStatus(item: DataFrameAnalyticsListRow): ViewLinkStatusReturn {
const viewLinkStatus: ViewLinkStatusReturn = { disabled: false };
const progressStats = getDataFrameAnalyticsProgressPhase(item.stats);
const jobFailed = isDataFrameAnalyticsFailed(item.stats.state);
const jobNotStarted = progressStats.currentPhase === 1 && progressStats.progress === 0;
const jobFinished =
isDataFrameAnalyticsStopped(item.stats.state) &&
progressStats.currentPhase === progressStats.totalPhases &&
progressStats.progress === 100;
const isUnknownJobType =
!isRegressionAnalysis(item.config.analysis) &&
!isOutlierAnalysis(item.config.analysis) &&
!isClassificationAnalysis(item.config.analysis);
const disabled = !jobFinished || jobFailed || isUnknownJobType;
if (disabled) {
viewLinkStatus.disabled = true;
if (isUnknownJobType) {
viewLinkStatus.tooltipContent = unknownJobTypeMessage;
} else if (jobFailed) {
viewLinkStatus.tooltipContent = jobFailedMessage;
} else if (jobNotStarted) {
viewLinkStatus.tooltipContent = jobNotStartedMessage;
} else if (!jobFinished) {
viewLinkStatus.tooltipContent = jobNotFinishedMessage;
}
}
return viewLinkStatus;
}

View file

@ -8,16 +8,13 @@ import React, { FC } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
import {
getAnalysisType,
isRegressionAnalysis,
isOutlierAnalysis,
isClassificationAnalysis,
} from '../../../../common/analytics';
import { getAnalysisType } from '../../../../common/analytics';
import { useMlKibana } from '../../../../../contexts/kibana';
import { getResultsUrl, DataFrameAnalyticsListRow } from '../analytics_list/common';
import { getViewLinkStatus } from './get_view_link_status';
interface ViewButtonProps {
item: DataFrameAnalyticsListRow;
isManagementTable: boolean;
@ -30,11 +27,8 @@ export const ViewButton: FC<ViewButtonProps> = ({ item, isManagementTable }) =>
},
} = useMlKibana();
const { disabled, tooltipContent } = getViewLinkStatus(item);
const analysisType = getAnalysisType(item.config.analysis);
const buttonDisabled =
!isRegressionAnalysis(item.config.analysis) &&
!isOutlierAnalysis(item.config.analysis) &&
!isClassificationAnalysis(item.config.analysis);
const url = getResultsUrl(item.id, analysisType);
const navigator = isManagementTable
@ -52,7 +46,7 @@ export const ViewButton: FC<ViewButtonProps> = ({ item, isManagementTable }) =>
data-test-subj="mlAnalyticsJobViewButton"
flush="left"
iconType="visTable"
isDisabled={buttonDisabled}
isDisabled={disabled}
onClick={navigator}
size="s"
>
@ -60,15 +54,9 @@ export const ViewButton: FC<ViewButtonProps> = ({ item, isManagementTable }) =>
</EuiButtonEmpty>
);
if (buttonDisabled) {
if (disabled) {
return (
<EuiToolTip
position="top"
content={i18n.translate('xpack.ml.dataframe.analyticsList.viewActionToolTipContent', {
defaultMessage:
'There is no results page available for this type of data frame analytics job.',
})}
>
<EuiToolTip position="top" content={tooltipContent}>
{button}
</EuiToolTip>
);