diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx index 858ab58b53f4b..8e7aecf429ad0 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx @@ -97,6 +97,7 @@ jest.mock('../../../../../util/index_utils', () => { }; } ), + isCcsIndexPattern: (a: string) => a.includes(':'), }; }); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index cbc5a226eb319..b6424c12283ef 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -25,7 +25,7 @@ import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana'; import { getNestedProperty } from '../../../../../util/object_utils'; -import { getIndexPatternAndSavedSearch } from '../../../../../util/index_utils'; +import { getIndexPatternAndSavedSearch, isCcsIndexPattern } from '../../../../../util/index_utils'; const fixedPageSize: number = 8; @@ -61,7 +61,7 @@ export const SourceSelection: FC = ({ onClose }) => { indexPatternTitle = indexPatternAndSavedSearch.indexPattern?.title ?? ''; } - if (indexPatternTitle.includes(':')) { + if (isCcsIndexPattern(indexPatternTitle)) { setIsCcsCallOut(true); if (type === 'search') { setCcsCallOutBodyText( diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts index 8702d35be8ac3..eba5a954fadc2 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts @@ -24,10 +24,12 @@ import { CategorizationAnalyzer, CategoryFieldExample, FieldExampleCheck, + VALIDATION_RESULT, } from '../../../../../../common/types/categories'; import { getRichDetectors } from './util/general'; import { CategorizationExamplesLoader } from '../results_loader'; import { getNewJobDefaults } from '../../../../services/ml_server_info'; +import { isCcsIndexPattern } from '../../../../util/index_utils'; export class CategorizationJobCreator extends JobCreator { protected _type: JOB_TYPE = JOB_TYPE.CATEGORIZATION; @@ -43,6 +45,7 @@ export class CategorizationJobCreator extends JobCreator { private _categorizationAnalyzer: CategorizationAnalyzer = {}; private _defaultCategorizationAnalyzer: CategorizationAnalyzer; private _partitionFieldName: string | null = null; + private _ccsVersionFailure: boolean = false; constructor( indexPattern: IndexPattern, @@ -126,9 +129,38 @@ export class CategorizationJobCreator extends JobCreator { this._validationChecks = validationChecks; this._overallValidStatus = overallValidStatus; + this._ccsVersionFailure = this._checkCcsFailure(examples, overallValidStatus, validationChecks); + if (this._ccsVersionFailure === true) { + // if the index pattern contains a cross-cluster search, one of the clusters may + // be on a version which doesn't support the fields API (e.g. 6.8) + // and so the categorization examples endpoint will fail + // if this is the case, we need to allow the user to progress in the wizard. + this._overallValidStatus = CATEGORY_EXAMPLES_VALIDATION_STATUS.VALID; + } + this._wizardInitialized$.next(true); - return { examples, sampleSize, overallValidStatus, validationChecks }; + return { + examples, + sampleSize, + overallValidStatus, + validationChecks, + ccsVersionFailure: this._ccsVersionFailure, + }; + } + + // Check to see if the examples failed due to a cross-cluster search being used + private _checkCcsFailure( + examples: CategoryFieldExample[], + status: CATEGORY_EXAMPLES_VALIDATION_STATUS, + checks: FieldExampleCheck[] + ) { + return ( + examples.length === 0 && + status === CATEGORY_EXAMPLES_VALIDATION_STATUS.INVALID && + checks[0]?.id === VALIDATION_RESULT.NO_EXAMPLES && + isCcsIndexPattern(this.indexPatternTitle) + ); } public get categoryFieldExamples() { diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/invalid_ccs_version_valid_callout.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/invalid_ccs_version_valid_callout.tsx new file mode 100644 index 0000000000000..112634b83780d --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/invalid_ccs_version_valid_callout.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FC } from 'react'; +import { EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +export const InvalidCssVersionCallout: FC = () => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/metric_selection.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/metric_selection.tsx index 8a2b9db77bfb2..34cba31aa17a5 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/metric_selection.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/categorization_view/metric_selection.tsx @@ -17,6 +17,7 @@ import { CategorizationPerPartitionField } from '../categorization_partition_fie import { FieldExamples } from './field_examples'; import { ExamplesValidCallout } from './examples_valid_callout'; +import { InvalidCssVersionCallout } from './invalid_ccs_version_valid_callout'; import { CategoryFieldExample, FieldExampleCheck, @@ -33,6 +34,7 @@ export const CategorizationDetectors: FC = ({ setIsValid }) => { const jobCreator = jc as CategorizationJobCreator; const [loadingData, setLoadingData] = useState(false); + const [ccsVersionFailure, setCcsVersionFailure] = useState(false); const [start, setStart] = useState(jobCreator.start); const [end, setEnd] = useState(jobCreator.end); const [categorizationAnalyzerString, setCategorizationAnalyzerString] = useState( @@ -85,10 +87,12 @@ export const CategorizationDetectors: FC = ({ setIsValid }) => { examples, overallValidStatus: tempOverallValidStatus, validationChecks: tempValidationChecks, + ccsVersionFailure: tempCcsVersionFailure, } = await jobCreator.loadCategorizationFieldExamples(); setFieldExamples(examples); setOverallValidStatus(tempOverallValidStatus); setValidationChecks(tempValidationChecks); + setCcsVersionFailure(tempCcsVersionFailure); setLoadingData(false); } catch (error) { setLoadingData(false); @@ -96,11 +100,13 @@ export const CategorizationDetectors: FC = ({ setIsValid }) => { setValidationChecks([]); setOverallValidStatus(CATEGORY_EXAMPLES_VALIDATION_STATUS.INVALID); getToastNotificationService().displayErrorToast(error); + setCcsVersionFailure(false); } } else { setFieldExamples(null); setValidationChecks([]); setOverallValidStatus(CATEGORY_EXAMPLES_VALIDATION_STATUS.INVALID); + setCcsVersionFailure(false); } setIsValid(categorizationFieldName !== null); } @@ -119,7 +125,7 @@ export const CategorizationDetectors: FC = ({ setIsValid }) => {
)} - {fieldExamples !== null && loadingData === false && ( + {ccsVersionFailure === false && fieldExamples !== null && loadingData === false && ( <> = ({ setIsValid }) => { )} + {ccsVersionFailure === true && } diff --git a/x-pack/plugins/ml/public/application/util/index_utils.ts b/x-pack/plugins/ml/public/application/util/index_utils.ts index 4faa77b2fbc34..9d705c8cd725f 100644 --- a/x-pack/plugins/ml/public/application/util/index_utils.ts +++ b/x-pack/plugins/ml/public/application/util/index_utils.ts @@ -146,3 +146,11 @@ export function timeBasedIndexCheck(indexPattern: IndexPattern, showNotification return true; } } + +/** + * Returns true if the index pattern contains a : + * which means it is cross-cluster + */ +export function isCcsIndexPattern(indexPatternTitle: string) { + return indexPatternTitle.includes(':'); +}