From c7caac61a2b03fbc8cf6ac3915ecb1cee72db29b Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Mon, 5 Oct 2020 19:23:13 +0200 Subject: [PATCH] [ML] Data Frame Analytics: Expandable sections for classification and regression (#79414) Applies the expandable section based layout to the results pages of classification and regression analytics jobs. --- .../_classification_exploration.scss | 2 +- .../classification_exploration.tsx | 28 +- .../evaluate_panel.tsx | 296 ++++++------ .../expandable_section.scss | 4 + .../expandable_section/expandable_section.tsx | 43 +- .../expandable_section_analytics.tsx | 146 ++++++ .../expandable_section_results.tsx | 161 +++++++ .../components/expandable_section/index.ts | 8 +- .../exploration_page_wrapper.tsx | 98 +++- .../exploration_results_table.tsx | 180 +------ .../exploration_title/exploration_title.tsx | 15 - .../components/exploration_title/index.ts | 7 - .../index_pattern_prompt.tsx | 3 +- .../job_config_error_callout.tsx | 2 - .../loading_panel/loading_panel.tsx | 11 +- .../outlier_exploration.tsx | 229 +-------- .../regression_exploration/evaluate_panel.tsx | 438 +++++++++--------- .../feature_importance_summary.tsx | 139 +++--- .../pages/analytics_exploration/page.tsx | 2 - .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - .../ml/data_frame_analytics_results.ts | 4 +- 22 files changed, 942 insertions(+), 880 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_analytics.tsx create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/exploration_title.tsx delete mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/index.ts diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss index 102f6630f2ee..00463affa0d0 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/_classification_exploration.scss @@ -23,7 +23,7 @@ .mlDataFrameAnalyticsClassification__actualLabel { float: left; width: 80px; - padding-top: $euiSize * 4 + $euiSizeXS; + padding-top: $euiSize * 4; } /* diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx index 833b4a78178d..f03fe2dae778 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx @@ -17,17 +17,19 @@ interface Props { } export const ClassificationExploration: FC = ({ jobId, defaultIsTraining }) => ( - +
+ +
); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx index 86e2c5fd2fb9..f37f649ac259 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx @@ -6,7 +6,7 @@ import './_classification_exploration.scss'; -import React, { FC, useState, useEffect, Fragment } from 'react'; +import React, { FC, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -15,7 +15,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip, - EuiPanel, EuiSpacer, EuiText, EuiTitle, @@ -30,7 +29,6 @@ import { DataFrameAnalyticsConfig, } from '../../../../common'; import { isKeywordAndTextType } from '../../../../common/fields'; -import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; import { isResultsSearchBoolQuery, @@ -39,7 +37,9 @@ import { ResultsSearchQuery, ANALYSIS_CONFIG_TYPE, } from '../../../../common/analytics'; -import { LoadingPanel } from '../loading_panel'; + +import { ExpandableSection, HEADER_ITEMS_LOADING } from '../expandable_section'; + import { getColumnData, ACTUAL_CLASS_ID, @@ -47,7 +47,7 @@ import { getTrailingControlColumns, } from './column_data'; -interface Props { +export interface EvaluatePanelProps { jobConfig: DataFrameAnalyticsConfig; jobStatus?: DATA_FRAME_TASK_STATE; searchQuery: ResultsSearchQuery; @@ -90,7 +90,7 @@ function getHelpText(dataSubsetTitle: string) { return helpText; } -export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) => { +export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) => { const { services: { docLinks }, } = useMlKibana(); @@ -272,10 +272,6 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) return {columnId === ACTUAL_CLASS_ID ? cellValue : accuracy}; }; - if (isLoading === true) { - return ; - } - const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks; const showTrailingColumns = columnsData.length > MAX_COLUMNS; @@ -288,137 +284,159 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) showTrailingColumns === true && showFullColumns === false ? MAX_COLUMNS : columnsData.length; return ( - -
- - - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle', - { - defaultMessage: 'Evaluation of classification job ID {jobId}', - values: { jobId: jobConfig.id }, - } - )} - - - - {jobStatus !== undefined && ( - - {getTaskStateBadge(jobStatus)} - - )} - - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.classificationExploration.classificationDocsLink', - { - defaultMessage: 'Classification evaluation docs ', - } - )} - - - -
- {error !== null && } - {error === null && ( - -
- - - {getHelpText(dataSubsetTitle)} - - - - - -
- {docsCount !== null && ( - - - - )} - {/* BEGIN TABLE ELEMENTS */} - -
-
- - - -
-
- {columns.length > 0 && columnsData.length > 0 && ( - <> -
- - - -
- - + + } + docsLink={ + + {i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.classificationDocsLink', + { + defaultMessage: 'Classification evaluation docs ', + } + )} + + } + headerItems={ + !isLoading + ? [ + ...(jobStatus !== undefined + ? [ { - defaultMessage: 'Classification confusion matrix', - } - )} - columns={shownColumns} - columnVisibility={{ visibleColumns, setVisibleColumns }} - rowCount={rowCount} - renderCellValue={renderCellValue} - inMemory={{ level: 'sorting' }} - toolbarVisibility={{ - showColumnSelector: true, - showStyleSelector: false, - showFullScreenSelector: false, - showSortSelector: false, - }} - popoverContents={popoverContents} - gridStyle={{ rowHover: 'none' }} - trailingControlColumns={ - showTrailingColumns === true && showFullColumns === false - ? getTrailingControlColumns(extraColumns, setShowFullColumns) - : undefined - } - /> + id: 'jobStatus', + label: i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobStatusLabel', + { + defaultMessage: 'Job status', + } + ), + value: jobStatus, + }, + ] + : []), + ...(docsCount !== null + ? [ + { + id: 'docsEvaluated', + label: i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount', + { + defaultMessage: '{docsCount, plural, one {doc} other {docs}} evaluated', + values: { docsCount }, + } + ), + value: docsCount, + }, + ] + : []), + ] + : HEADER_ITEMS_LOADING + } + contentPadding={true} + content={ + !isLoading ? ( + <> + {error !== null && } + {error === null && ( + <> + + + {getHelpText(dataSubsetTitle)} + + + + + + {/* BEGIN TABLE ELEMENTS */} + +
+
+ + + +
+
+ {columns.length > 0 && columnsData.length > 0 && ( + <> +
+ + + +
+ + + + )} +
+
)} -
-
-
- )} - {/* END TABLE ELEMENTS */} -
+ {/* END TABLE ELEMENTS */} + + ) : null + } + /> + + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss index e296744b2737..c1c80e8dbd2c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.scss @@ -1,3 +1,7 @@ .mlExpandableSection { padding: 0 $euiSizeS $euiSizeS $euiSizeS; } + +.mlExpandableSection-contentPadding { + padding: $euiSizeS; +} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx index 97fb8fd29e5a..fa7538b58033 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section.tsx @@ -29,9 +29,13 @@ const isHeaderItems = (arg: any): arg is HeaderItem[] => { return Array.isArray(arg); }; +export const HEADER_ITEMS_LOADING = 'header_items_loading'; + export interface ExpandableSectionProps { content: ReactNode; - headerItems?: HeaderItem[] | 'loading'; + contentPadding?: boolean; + docsLink?: ReactNode; + headerItems?: HeaderItem[] | typeof HEADER_ITEMS_LOADING; isExpanded?: boolean; dataTestId: string; title: ReactNode; @@ -45,8 +49,10 @@ export const ExpandableSection: FC = ({ // callback. isExpanded: isExpandedDefault = true, content, + contentPadding = false, dataTestId, title, + docsLink, }) => { const [isExpanded, setIsExpanded] = useState(isExpandedDefault); const toggleExpanded = () => { @@ -56,16 +62,21 @@ export const ExpandableSection: FC = ({ return (
- - {title} - - {headerItems === 'loading' && } + + + + {title} + + + {docsLink !== undefined && {docsLink}} + + {headerItems === HEADER_ITEMS_LOADING && } {isHeaderItems(headerItems) && ( {headerItems.map(({ label, value, id }) => ( @@ -82,13 +93,19 @@ export const ExpandableSection: FC = ({ {value} )} - {label === undefined && value} + {label === undefined && ( + + {value} + + )} ))} )}
- {isExpanded && content} + {isExpanded && ( +
{content}
+ )}
); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_analytics.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_analytics.tsx new file mode 100644 index 000000000000..0d8a0df30b4e --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_analytics.tsx @@ -0,0 +1,146 @@ +/* + * 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, { useEffect, useState, FC } from 'react'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiHorizontalRule, EuiLoadingSpinner, EuiSpacer, EuiText } from '@elastic/eui'; + +import type { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics'; + +import { ml } from '../../../../../services/ml_api_service'; + +import { getAnalysisType } from '../../../../common'; + +import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics'; +import { + DataFrameAnalyticsListRow, + DATA_FRAME_MODE, +} from '../../../analytics_management/components/analytics_list/common'; +import { ExpandedRow } from '../../../analytics_management/components/analytics_list/expanded_row'; + +import { + ExpandableSection, + ExpandableSectionProps, + HEADER_ITEMS_LOADING, +} from './expandable_section'; + +const getAnalyticsSectionHeaderItems = ( + expandedRowItem: DataFrameAnalyticsListRow | undefined +): ExpandableSectionProps['headerItems'] => { + if (expandedRowItem === undefined) { + return HEADER_ITEMS_LOADING; + } + + const sourceIndex = Array.isArray(expandedRowItem.config.source.index) + ? expandedRowItem.config.source.index.join() + : expandedRowItem.config.source.index; + + return [ + { + id: 'analysisTypeLabel', + label: ( + + ), + value: expandedRowItem.job_type, + }, + { + id: 'analysisSourceIndexLabel', + label: ( + + ), + value: sourceIndex, + }, + { + id: 'analysisDestinationIndexLabel', + label: ( + + ), + value: expandedRowItem.config.dest.index, + }, + ]; +}; + +interface ExpandableSectionAnalyticsProps { + jobId: string; +} + +export const ExpandableSectionAnalytics: FC = ({ jobId }) => { + const [expandedRowItem, setExpandedRowItem] = useState(); + + const fetchStats = async () => { + const analyticsConfigs = await ml.dataFrameAnalytics.getDataFrameAnalytics(jobId); + const analyticsStats = await ml.dataFrameAnalytics.getDataFrameAnalyticsStats(jobId); + + const config = analyticsConfigs.data_frame_analytics[0]; + const stats = isGetDataFrameAnalyticsStatsResponseOk(analyticsStats) + ? analyticsStats.data_frame_analytics[0] + : undefined; + + if (stats === undefined) { + return; + } + + const newExpandedRowItem: DataFrameAnalyticsListRow = { + checkpointing: {}, + config, + id: config.id, + job_type: getAnalysisType(config.analysis) as DataFrameAnalysisConfigType, + mode: DATA_FRAME_MODE.BATCH, + state: stats.state, + stats, + }; + + setExpandedRowItem(newExpandedRowItem); + }; + + useEffect(() => { + fetchStats(); + }, [jobId]); + + const analyticsSectionHeaderItems = getAnalyticsSectionHeaderItems(expandedRowItem); + const analyticsSectionContent = ( + <> + + {expandedRowItem === undefined && ( + + + + + + )} + {expandedRowItem !== undefined && } + + ); + + return ( + <> + + } + /> + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx new file mode 100644 index 000000000000..e01a291b2738 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx @@ -0,0 +1,161 @@ +/* + * 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 } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiDataGridColumn, EuiSpacer, EuiText } from '@elastic/eui'; + +import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public'; + +import { + isClassificationAnalysis, + isRegressionAnalysis, +} from '../../../../../../../common/util/analytics_utils'; + +import { getToastNotifications } from '../../../../../util/dependency_cache'; +import { useColorRange, ColorRangeLegend } from '../../../../../components/color_range_legend'; +import { DataGrid, UseIndexDataReturnType } from '../../../../../components/data_grid'; +import { SavedSearchQuery } from '../../../../../contexts/ml'; + +import { defaultSearchQuery, DataFrameAnalyticsConfig, SEARCH_SIZE } from '../../../../common'; + +import { + ExpandableSection, + ExpandableSectionProps, + HEADER_ITEMS_LOADING, +} from '../expandable_section'; +import { IndexPatternPrompt } from '../index_pattern_prompt'; + +const showingDocs = i18n.translate( + 'xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText', + { + defaultMessage: 'Showing documents for which predictions exist', + } +); + +const showingFirstDocs = i18n.translate( + 'xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText', + { + defaultMessage: 'Showing first {searchSize} documents for which predictions exist', + values: { searchSize: SEARCH_SIZE }, + } +); + +const getResultsSectionHeaderItems = ( + columnsWithCharts: EuiDataGridColumn[], + tableItems: Array>, + rowCount: number, + colorRange?: ReturnType +): ExpandableSectionProps['headerItems'] => { + return columnsWithCharts.length > 0 && tableItems.length > 0 + ? [ + { + id: 'explorationTableTotalDocs', + label: ( + + ), + value: rowCount, + }, + ...(colorRange !== undefined + ? [ + { + id: 'colorRangeLegend', + value: ( + + ), + }, + ] + : []), + ] + : HEADER_ITEMS_LOADING; +}; + +interface ExpandableSectionResultsProps { + colorRange?: ReturnType; + indexData: UseIndexDataReturnType; + indexPattern?: IndexPattern; + jobConfig?: DataFrameAnalyticsConfig; + needsDestIndexPattern: boolean; + searchQuery: SavedSearchQuery; +} + +export const ExpandableSectionResults: FC = ({ + colorRange, + indexData, + indexPattern, + jobConfig, + needsDestIndexPattern, + searchQuery, +}) => { + const { columnsWithCharts, tableItems } = indexData; + + // Results section header items and content + const resultsSectionHeaderItems = getResultsSectionHeaderItems( + columnsWithCharts, + tableItems, + indexData.rowCount, + colorRange + ); + const resultsSectionContent = ( + <> + {jobConfig !== undefined && needsDestIndexPattern && ( +
+ +
+ )} + {jobConfig !== undefined && + (isRegressionAnalysis(jobConfig.analysis) || + isClassificationAnalysis(jobConfig.analysis)) && ( + + {tableItems.length === SEARCH_SIZE ? showingFirstDocs : showingDocs} + + )} + {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && + indexPattern !== undefined && ( + <> + {columnsWithCharts.length > 0 && tableItems.length > 0 && ( + + )} + + )} + + ); + + return ( + <> + + } + /> + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts index ad7ce84902e8..3d9237922e19 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/index.ts @@ -4,4 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ExpandableSection, ExpandableSectionProps } from './expandable_section'; +export { + ExpandableSection, + ExpandableSectionProps, + HEADER_ITEMS_LOADING, +} from './expandable_section'; +export { ExpandableSectionAnalytics } from './expandable_section_analytics'; +export { ExpandableSectionResults } from './expandable_section_results'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx index 6b1b3fc1bb47..b03777fef6bd 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx @@ -4,20 +4,49 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, useState } from 'react'; +import React, { FC, useEffect, useState } from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; -import { useResultsViewConfig, DataFrameAnalyticsConfig } from '../../../../common'; -import { ResultsSearchQuery, defaultSearchQuery } from '../../../../common/analytics'; +import { useUrlState } from '../../../../../util/url_state'; + +import { + defaultSearchQuery, + getDefaultTrainingFilterQuery, + useResultsViewConfig, + DataFrameAnalyticsConfig, +} from '../../../../common'; +import { ResultsSearchQuery } from '../../../../common/analytics'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; +import { ExpandableSectionAnalytics } from '../expandable_section'; import { ExplorationResultsTable } from '../exploration_results_table'; +import { ExplorationQueryBar } from '../exploration_query_bar'; import { JobConfigErrorCallout } from '../job_config_error_callout'; import { LoadingPanel } from '../loading_panel'; import { FeatureImportanceSummaryPanelProps } from '../total_feature_importance_summary/feature_importance_summary'; +const filters = { + options: [ + { + id: 'training', + label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.trainingSubsetLabel', { + defaultMessage: 'Training', + }), + }, + { + id: 'testing', + label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.testingSubsetLabel', { + defaultMessage: 'Testing', + }), + }, + ], + columnId: 'ml.is_training', + key: { training: true, testing: false }, +}; + export interface EvaluatePanelProps { jobConfig: DataFrameAnalyticsConfig; jobStatus?: DATA_FRAME_TASK_STATE; @@ -50,7 +79,25 @@ export const ExplorationPageWrapper: FC = ({ needsDestIndexPattern, totalFeatureImportance, } = useResultsViewConfig(jobId); + const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); + const [globalState, setGlobalState] = useUrlState('_g'); + const [defaultQueryString, setDefaultQueryString] = useState(); + + useEffect(() => { + if (defaultIsTraining !== undefined && jobConfig !== undefined) { + // Apply defaultIsTraining filter + setSearchQuery( + getDefaultTrainingFilterQuery(jobConfig.dest.results_field, defaultIsTraining) + ); + setDefaultQueryString(`${jobConfig.dest.results_field}.is_training : ${defaultIsTraining}`); + // Clear defaultIsTraining from url + setGlobalState('ml', { + analysisType: globalState.ml.analysisType, + jobId: globalState.ml.jobId, + }); + } + }, [jobConfig?.dest.results_field]); if (jobConfigErrorMessage !== undefined || jobCapsServiceErrorMessage !== undefined) { return ( @@ -61,21 +108,54 @@ export const ExplorationPageWrapper: FC = ({ /> ); } + return ( <> + {typeof jobConfig?.description !== 'undefined' && ( + <> + {jobConfig?.description} + + + )} + + {indexPattern !== undefined && ( + <> + + + + + + + + + + + + + )} + {isLoadingJobConfig === true && jobConfig === undefined && } {isLoadingJobConfig === false && jobConfig !== undefined && isInitialized === true && ( - + )} + {isLoadingJobConfig === true && totalFeatureImportance === undefined && } {isLoadingJobConfig === false && totalFeatureImportance !== undefined && ( <> - )} - + {isLoadingJobConfig === true && jobConfig === undefined && } + {isLoadingJobConfig === false && jobConfig !== undefined && isInitialized === true && ( + + )} + {isLoadingJobConfig === true && jobConfig === undefined && } {isLoadingJobConfig === false && jobConfig !== undefined && @@ -86,9 +166,7 @@ export const ExplorationPageWrapper: FC = ({ jobConfig={jobConfig} jobStatus={jobStatus} needsDestIndexPattern={needsDestIndexPattern} - setEvaluateSearchQuery={setSearchQuery} - title={title} - defaultIsTraining={defaultIsTraining} + searchQuery={searchQuery} /> )} diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx index bd4079272c56..a6e95269b363 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx @@ -4,118 +4,37 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, FC, useEffect, useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; +import React, { FC } from 'react'; import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public'; -import { DataGrid } from '../../../../../components/data_grid'; -import { SavedSearchQuery } from '../../../../../contexts/ml'; import { getToastNotifications } from '../../../../../util/dependency_cache'; +import { useMlKibana } from '../../../../../contexts/kibana'; + +import { DataFrameAnalyticsConfig } from '../../../../common'; +import { ResultsSearchQuery } from '../../../../common/analytics'; -import { - DataFrameAnalyticsConfig, - MAX_COLUMNS, - SEARCH_SIZE, - defaultSearchQuery, - getAnalysisType, - getDefaultTrainingFilterQuery, -} from '../../../../common'; -import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; -import { ExplorationTitle } from '../exploration_title'; -import { ExplorationQueryBar } from '../exploration_query_bar'; -import { IndexPatternPrompt } from '../index_pattern_prompt'; + +import { ExpandableSectionResults } from '../expandable_section'; import { useExplorationResults } from './use_exploration_results'; -import { useMlKibana } from '../../../../../contexts/kibana'; -import { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics'; -import { useUrlState } from '../../../../../util/url_state'; - -const showingDocs = i18n.translate( - 'xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText', - { - defaultMessage: 'Showing documents for which predictions exist', - } -); - -const showingFirstDocs = i18n.translate( - 'xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText', - { - defaultMessage: 'Showing first {searchSize} documents for which predictions exist', - values: { searchSize: SEARCH_SIZE }, - } -); - -const filters = { - options: [ - { - id: 'training', - label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.trainingSubsetLabel', { - defaultMessage: 'Training', - }), - }, - { - id: 'testing', - label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.testingSubsetLabel', { - defaultMessage: 'Testing', - }), - }, - ], - columnId: 'ml.is_training', - key: { training: true, testing: false }, -}; interface Props { indexPattern: IndexPattern; jobConfig: DataFrameAnalyticsConfig; jobStatus?: DATA_FRAME_TASK_STATE; needsDestIndexPattern: boolean; - setEvaluateSearchQuery: React.Dispatch>; - title: string; - defaultIsTraining?: boolean; + searchQuery: ResultsSearchQuery; } export const ExplorationResultsTable: FC = React.memo( - ({ - indexPattern, - jobConfig, - jobStatus, - needsDestIndexPattern, - setEvaluateSearchQuery, - title, - defaultIsTraining, - }) => { + ({ indexPattern, jobConfig, jobStatus, needsDestIndexPattern, searchQuery }) => { const { services: { mlServices: { mlApiServices }, }, } = useMlKibana(); - const [globalState, setGlobalState] = useUrlState('_g'); - const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); - const [defaultQueryString, setDefaultQueryString] = useState(); - - useEffect(() => { - setEvaluateSearchQuery(searchQuery); - }, [JSON.stringify(searchQuery)]); - - useEffect(() => { - if (defaultIsTraining !== undefined) { - // Apply defaultIsTraining filter - setSearchQuery( - getDefaultTrainingFilterQuery(jobConfig.dest.results_field, defaultIsTraining) - ); - setDefaultQueryString(`${jobConfig.dest.results_field}.is_training : ${defaultIsTraining}`); - // Clear defaultIsTraining from url - setGlobalState('ml', { - analysisType: globalState.ml.analysisType, - jobId: globalState.ml.jobId, - }); - } - }, []); - - const analysisType = getAnalysisType(jobConfig.analysis); const classificationData = useExplorationResults( indexPattern, @@ -125,83 +44,20 @@ export const ExplorationResultsTable: FC = React.memo( mlApiServices ); - const docFieldsCount = classificationData.columnsWithCharts.length; - const { columnsWithCharts, tableItems, visibleColumns } = classificationData; - if (jobConfig === undefined || classificationData === undefined) { return null; } return ( - - {needsDestIndexPattern && } - - - - - - - {jobStatus !== undefined && ( - - {getTaskStateBadge(jobStatus)} - - )} - - - - - - {docFieldsCount > MAX_COLUMNS && ( - - {i18n.translate( - 'xpack.ml.dataframe.analytics.explorationResults.fieldSelection', - { - defaultMessage: - '{selectedFieldsLength, number} of {docFieldsCount, number} {docFieldsCount, plural, one {field} other {fields}} selected', - values: { selectedFieldsLength: visibleColumns.length, docFieldsCount }, - } - )} - - )} - - - - - {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && ( - - - - - - - - - - - - - - - - - )} - +
+ +
); } ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/exploration_title.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/exploration_title.tsx deleted file mode 100644 index f06c88c73df7..000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/exploration_title.tsx +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 } from 'react'; - -import { EuiTitle } from '@elastic/eui'; - -export const ExplorationTitle: FC<{ title: string }> = ({ title }) => ( - - {title} - -); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/index.ts deleted file mode 100644 index b34e61b3b5e7..000000000000 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_title/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { ExplorationTitle } from './exploration_title'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx index f478dc639da2..0353129212b0 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/index_pattern_prompt/index_pattern_prompt.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { EuiLink, EuiText } from '@elastic/eui'; import { useMlKibana } from '../../../../../contexts/kibana'; interface Props { @@ -42,7 +42,6 @@ export const IndexPatternPrompt: FC = ({ destIndex }) => { }} /> - ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx index 959f2d18d99f..261438cec729 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/job_config_error_callout/job_config_error_callout.tsx @@ -10,7 +10,6 @@ import { EuiCallOut, EuiLink, EuiPanel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ExplorationTitle } from '../exploration_title'; import { useMlKibana } from '../../../../../contexts/kibana'; const jobConfigErrorTitle = i18n.translate('xpack.ml.dataframe.analytics.jobConfig.errorTitle', { @@ -63,7 +62,6 @@ export const JobConfigErrorCallout: FC = ({ return ( - ( - - - + <> + + + + + ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx index 7d7f5efcae32..8fc248659975 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/outlier_exploration.tsx @@ -4,124 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useState, FC } from 'react'; +import React, { useState, FC } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; - -import { - EuiDataGridColumn, - EuiHorizontalRule, - EuiLoadingSpinner, - EuiSpacer, - EuiText, -} from '@elastic/eui'; - -import type { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics'; +import { EuiSpacer, EuiText } from '@elastic/eui'; import { useColorRange, COLOR_RANGE, COLOR_RANGE_SCALE, } from '../../../../../components/color_range_legend'; -import { ColorRangeLegend } from '../../../../../components/color_range_legend'; -import { DataGrid } from '../../../../../components/data_grid'; import { SavedSearchQuery } from '../../../../../contexts/ml'; -import { getToastNotifications } from '../../../../../util/dependency_cache'; -import { ml } from '../../../../../services/ml_api_service'; -import { getAnalysisType, defaultSearchQuery, useResultsViewConfig } from '../../../../common'; +import { defaultSearchQuery, useResultsViewConfig } from '../../../../common'; -import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics'; - -import { - DataFrameAnalyticsListRow, - DATA_FRAME_MODE, -} from '../../../analytics_management/components/analytics_list/common'; -import { ExpandedRow } from '../../../analytics_management/components/analytics_list/expanded_row'; - -import { ExpandableSection, ExpandableSectionProps } from '../expandable_section'; +import { ExpandableSectionAnalytics, ExpandableSectionResults } from '../expandable_section'; import { ExplorationQueryBar } from '../exploration_query_bar'; -import { IndexPatternPrompt } from '../index_pattern_prompt'; import { getFeatureCount } from './common'; import { useOutlierData } from './use_outlier_data'; -const getAnalyticsSectionHeaderItems = ( - expandedRowItem: DataFrameAnalyticsListRow | undefined -): ExpandableSectionProps['headerItems'] => { - return expandedRowItem !== undefined - ? [ - { - id: 'analysisTypeLabel', - label: ( - - ), - value: expandedRowItem.job_type, - }, - { - id: 'analysisSourceIndexLabel', - label: ( - - ), - value: expandedRowItem.config.source.index, - }, - { - id: 'analysisDestinationIndexLabel', - label: ( - - ), - value: expandedRowItem.config.dest.index, - }, - ] - : 'loading'; -}; - -const getResultsSectionHeaderItems = ( - columnsWithCharts: EuiDataGridColumn[], - tableItems: Array>, - rowCount: number, - colorRange: ReturnType -): ExpandableSectionProps['headerItems'] => { - return columnsWithCharts.length > 0 && tableItems.length > 0 - ? [ - { - id: 'explorationTableTotalDocs', - label: ( - - ), - value: rowCount, - }, - { - id: 'colorRangeLegend', - value: ( - - ), - }, - ] - : 'loading'; -}; - export type TableItem = Record; interface ExplorationProps { @@ -141,89 +42,14 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1 ); - const [expandedRowItem, setExpandedRowItem] = useState(); - - const fetchStats = async () => { - const analyticsConfigs = await ml.dataFrameAnalytics.getDataFrameAnalytics(jobId); - const analyticsStats = await ml.dataFrameAnalytics.getDataFrameAnalyticsStats(jobId); - - const config = analyticsConfigs.data_frame_analytics[0]; - const stats = isGetDataFrameAnalyticsStatsResponseOk(analyticsStats) - ? analyticsStats.data_frame_analytics[0] - : undefined; - - if (stats === undefined) { - return; - } - - const newExpandedRowItem: DataFrameAnalyticsListRow = { - checkpointing: {}, - config, - id: config.id, - job_type: getAnalysisType(config.analysis) as DataFrameAnalysisConfigType, - mode: DATA_FRAME_MODE.BATCH, - state: stats.state, - stats, - }; - - setExpandedRowItem(newExpandedRowItem); - }; - - useEffect(() => { - fetchStats(); - }, [jobConfig?.id]); - - // Analytics section header items and content - const analyticsSectionHeaderItems = getAnalyticsSectionHeaderItems(expandedRowItem); - const analyticsSectionContent = ( - <> - - {expandedRowItem === undefined && ( - - - - - - )} - {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && - indexPattern !== undefined && - jobConfig !== undefined && - columnsWithCharts.length > 0 && - tableItems.length > 0 && - expandedRowItem !== undefined && } - - ); - - // Results section header items and content - const resultsSectionHeaderItems = getResultsSectionHeaderItems( - columnsWithCharts, - tableItems, - outlierData.rowCount, - colorRange - ); - const resultsSectionContent = ( - <> - {jobConfig !== undefined && needsDestIndexPattern && ( - - )} - {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && - indexPattern !== undefined && ( - <> - - {columnsWithCharts.length > 0 && tableItems.length > 0 && ( - - )} - - )} - - ); - return ( <> + {typeof jobConfig?.description !== 'undefined' && ( + <> + {jobConfig?.description} + + + )} {(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && indexPattern !== undefined && ( <> @@ -231,34 +57,15 @@ export const OutlierExploration: FC = React.memo(({ jobId }) = )} - - - } + {typeof jobConfig?.id === 'string' && } + - - - - - } - /> - ); }); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx index 197160a1be4d..4350583a907a 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/evaluate_panel.tsx @@ -11,7 +11,6 @@ import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, - EuiPanel, EuiSpacer, EuiText, EuiTitle, @@ -27,9 +26,7 @@ import { Eval, DataFrameAnalyticsConfig, } from '../../../../common'; -import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; -import { EvaluateStat } from './evaluate_stat'; import { isResultsSearchBoolQuery, isRegressionEvaluateResponse, @@ -38,6 +35,10 @@ import { EMPTY_STAT, } from '../../../../common/analytics'; +import { ExpandableSection } from '../expandable_section'; + +import { EvaluateStat } from './evaluate_stat'; + interface Props { jobConfig: DataFrameAnalyticsConfig; jobStatus?: DATA_FRAME_TASK_STATE; @@ -219,30 +220,16 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) }, [JSON.stringify(searchQuery)]); return ( - - - - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle', - { - defaultMessage: 'Evaluation of regression job ID {jobId}', - values: { jobId: jobConfig.id }, - } - )} - - - - {jobStatus !== undefined && ( - - {getTaskStateBadge(jobStatus)} - - )} - - - - + <> + + } + docsLink={ = ({ jobConfig, jobStatus, searchQuery }) } )} - - + } + headerItems={ + jobStatus !== undefined + ? [ + { + id: 'jobStatus', + label: i18n.translate( + 'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobStatusLabel', + { + defaultMessage: 'Job status', + } + ), + value: jobStatus, + }, + ] + : [] + } + contentPadding={true} + content={ + + + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle', + { + defaultMessage: 'Generalization error', + } + )} + + + {generalizationDocsCount !== null && ( + + + {isTrainingFilter === true && generalizationDocsCount === 0 && ( + + )} + + )} + + + + + {/* First row stats */} + + + + + + + + + + + {/* Second row stats */} + + + + + + + + + + + + + {generalizationEval.error !== null && ( + + + {isTrainingFilter === true && + generalizationDocsCount === 0 && + generalizationEval.error.includes('No documents found') + ? i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTestingDocsError', + { + defaultMessage: 'No testing documents found', + } + ) + : generalizationEval.error} + + + )} + + + + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.trainingErrorTitle', + { + defaultMessage: 'Training error', + } + )} + + + {trainingDocsCount !== null && ( + + + {isTrainingFilter === false && trainingDocsCount === 0 && ( + + )} + + )} + + + + + {/* First row stats */} + + + + + + + + + + + {/* Second row stats */} + + + + + + + + + + + + + {trainingEval.error !== null && ( + + + {isTrainingFilter === false && + trainingDocsCount === 0 && + trainingEval.error.includes('No documents found') + ? i18n.translate( + 'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTrainingDocsError', + { + defaultMessage: 'No training documents found', + } + ) + : trainingEval.error} + + + )} + + + + } + /> - - - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle', - { - defaultMessage: 'Generalization error', - } - )} - - - {generalizationDocsCount !== null && ( - - - {isTrainingFilter === true && generalizationDocsCount === 0 && ( - - )} - - )} - - - - - {/* First row stats */} - - - - - - - - - - - {/* Second row stats */} - - - - - - - - - - - - - {generalizationEval.error !== null && ( - - - {isTrainingFilter === true && - generalizationDocsCount === 0 && - generalizationEval.error.includes('No documents found') - ? i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTestingDocsError', - { - defaultMessage: 'No testing documents found', - } - ) - : generalizationEval.error} - - - )} - - - - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.trainingErrorTitle', - { - defaultMessage: 'Training error', - } - )} - - - {trainingDocsCount !== null && ( - - - {isTrainingFilter === false && trainingDocsCount === 0 && ( - - )} - - )} - - - - - {/* First row stats */} - - - - - - - - - - - {/* Second row stats */} - - - - - - - - - - - - - {trainingEval.error !== null && ( - - - {isTrainingFilter === false && - trainingDocsCount === 0 && - trainingEval.error.includes('No documents found') - ? i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTrainingDocsError', - { - defaultMessage: 'No training documents found', - } - ) - : trainingEval.error} - - - )} - - - - + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx index f7ac717caef2..32ea2cfe8145 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx @@ -5,15 +5,7 @@ */ import React, { FC, useCallback, useMemo } from 'react'; -import { - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiIconTip, - EuiPanel, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; +import { EuiButtonEmpty, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Chart, @@ -38,6 +30,9 @@ import { } from '../../../../../../../common/types/feature_importance'; import { useMlKibana } from '../../../../../contexts/kibana'; + +import { ExpandableSection } from '../expandable_section'; + const { euiColorMediumShade } = euiVars; const axisColor = euiColorMediumShade; @@ -194,71 +189,67 @@ export const FeatureImportanceSummaryPanel: FC Number(d.toPrecision(3)).toString(), []); return ( - -
- - - - - - - - - - - - - - - - - - - - - - -
- - + <> + + } + docsLink={ + + + + } + headerItems={[ + { + id: 'FeatureImportanceSummary', + value: tooltipContent, + }, + ]} + content={ + + - - - - -
+ + + + + } + /> + + ); }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx index d2767a9612e3..0144d369c46f 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/page.tsx @@ -12,7 +12,6 @@ import { EuiPageContentBody, EuiPageContentHeader, EuiPageContentHeaderSection, - EuiSpacer, EuiTitle, } from '@elastic/eui'; @@ -42,7 +41,6 @@ export const Page: FC<{ - {analysisType === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION && ( )} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 420df7618b93..2738398b3ebc 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -10550,7 +10550,6 @@ "xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTestingHelpText": "データセットをテストするための正規化された混同行列", "xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTooltip": "マルチクラス混同行列には、分析が実際のクラスで正しくデータポイントを分類した発生数と、別のクラスで誤分類した発生数が含まれます。", "xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTrainingHelpText": "データセットを学習するための正規化された混同行列", - "xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle": "分類ジョブID {jobId}の評価", "xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました", "xpack.ml.dataframe.analytics.classificationExploration.showActions": "アクションを表示", "xpack.ml.dataframe.analytics.classificationExploration.showAllColumns": "すべての列を表示", @@ -10753,13 +10752,11 @@ "xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorTitle": "クエリをパースできません。", "xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle": "機能影響スコア", "xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText": "予測があるドキュメントを示す", - "xpack.ml.dataframe.analytics.explorationResults.fieldSelection": "{docFieldsCount, number}件中 showing {selectedFieldsLength, number}件の{docFieldsCount, plural, one {フィールド} other {フィールド}}", "xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText": "予測がある最初の{searchSize}のドキュメントを示す", "xpack.ml.dataframe.analytics.indexPatternPromptLinkText": "インデックスパターンを作成します", "xpack.ml.dataframe.analytics.indexPatternPromptMessage": "{destIndex}のインデックス{destIndex}. {linkToIndexPatternManagement}にはインデックスパターンが存在しません。", "xpack.ml.dataframe.analytics.jobCaps.errorTitle": "結果を取得できません。インデックスのフィールドデータの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.jobConfig.errorTitle": "結果を取得できません。ジョブ構成データの読み込み中にエラーが発生しました。", - "xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle": "回帰ジョブID {jobId}の評価", "xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました", "xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "一般化エラー", "xpack.ml.dataframe.analytics.regressionExploration.generalizationFilterText": ".学習データをフィルタリングしています。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a17be0f992b6..94fa87e8206c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -10556,7 +10556,6 @@ "xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTestingHelpText": "用于测试数据集的标准化混淆矩阵", "xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTooltip": "多类混淆矩阵包含分析使用数据点的实际类正确分类数据点的次数以及分析使用其他类错误分类这些数据点的次数", "xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTrainingHelpText": "用于训练数据集的标准化混淆矩阵", - "xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle": "分类作业 ID {jobId} 的评估", "xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估", "xpack.ml.dataframe.analytics.classificationExploration.showActions": "显示操作", "xpack.ml.dataframe.analytics.classificationExploration.showAllColumns": "显示所有列", @@ -10759,13 +10758,11 @@ "xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorTitle": "无法解析查询。", "xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle": "功能影响分数", "xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText": "正在显示有相关预测存在的文档", - "xpack.ml.dataframe.analytics.explorationResults.fieldSelection": "已选择 {docFieldsCount, number} 个{docFieldsCount, plural, one {字段} other {字段}}中的 {selectedFieldsLength, number} 个", "xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText": "正在显示有相关预测存在的前 {searchSize} 个文档", "xpack.ml.dataframe.analytics.indexPatternPromptLinkText": "创建索引模式", "xpack.ml.dataframe.analytics.indexPatternPromptMessage": "不存在索引 {destIndex} 的索引模式。{destIndex} 的{linkToIndexPatternManagement}。", "xpack.ml.dataframe.analytics.jobCaps.errorTitle": "无法提取结果。加载索引的字段数据时发生错误。", "xpack.ml.dataframe.analytics.jobConfig.errorTitle": "无法提取结果。加载作业配置数据时发生错误。", - "xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle": "回归作业 ID {jobId} 的评估", "xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估", "xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "泛化误差", "xpack.ml.dataframe.analytics.regressionExploration.generalizationFilterText": ".筛留训练数据。", diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_results.ts b/x-pack/test/functional/services/ml/data_frame_analytics_results.ts index 8a72badebd92..a4d8fa8e692b 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_results.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_results.ts @@ -15,7 +15,7 @@ export function MachineLearningDataFrameAnalyticsResultsProvider({ return { async assertRegressionEvaluatePanelElementsExists() { - await testSubjects.existOrFail('mlDFAnalyticsRegressionExplorationEvaluatePanel'); + await testSubjects.existOrFail('mlDFExpandableSection-RegressionEvaluation'); await testSubjects.existOrFail('mlDFAnalyticsRegressionGenMSEstat'); await testSubjects.existOrFail('mlDFAnalyticsRegressionGenRSquaredStat'); await testSubjects.existOrFail('mlDFAnalyticsRegressionTrainingMSEstat'); @@ -27,7 +27,7 @@ export function MachineLearningDataFrameAnalyticsResultsProvider({ }, async assertClassificationEvaluatePanelElementsExists() { - await testSubjects.existOrFail('mlDFAnalyticsClassificationExplorationEvaluatePanel'); + await testSubjects.existOrFail('mlDFExpandableSection-ClassificationEvaluation'); await testSubjects.existOrFail('mlDFAnalyticsClassificationExplorationConfusionMatrix'); },