Skip to content

Commit 6519b83

Browse files
[ML] Data frame analytics: Adds map view (#81666)
* add analytics map endpoint and server model * add map action to job and models list * wip:fetch models for jobs. Use url generator * get models when extending node. deduplicate elements * add job type icons. disable map action if job not finished. * move shared const to common dir * persist map tab. handle indexPattern from visualizer * use url generator in models list * temporarily disable delete action in flyout * update legend style. make map horizontal * update dfa model to use spaces changes * format creation time * update from indexPattern to index.remove refresh button * handle index patterns with wildcard
1 parent 3151e7e commit 6519b83

File tree

37 files changed

+1657
-27
lines changed

37 files changed

+1657
-27
lines changed

x-pack/plugins/ml/common/constants/data_frame_analytics.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ export const ANALYSIS_CONFIG_TYPE = {
1010
CLASSIFICATION: 'classification',
1111
} as const;
1212
export const DEFAULT_RESULTS_FIELD = 'ml';
13+
14+
export const JOB_MAP_NODE_TYPES = {
15+
ANALYTICS: 'analytics',
16+
TRANSFORM: 'transform',
17+
INDEX: 'index',
18+
INFERENCE_MODEL: 'inferenceModel',
19+
} as const;
20+
21+
export type JobMapNodeTypes = typeof JOB_MAP_NODE_TYPES[keyof typeof JOB_MAP_NODE_TYPES];

x-pack/plugins/ml/common/constants/ml_url_generator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const ML_PAGES = {
1212
SINGLE_METRIC_VIEWER: 'timeseriesexplorer',
1313
DATA_FRAME_ANALYTICS_JOBS_MANAGE: 'data_frame_analytics',
1414
DATA_FRAME_ANALYTICS_EXPLORATION: 'data_frame_analytics/exploration',
15+
DATA_FRAME_ANALYTICS_MAP: 'data_frame_analytics/map',
1516
/**
1617
* Page: Data Visualizer
1718
*/

x-pack/plugins/ml/common/types/ml_url_generator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export interface DataFrameAnalyticsQueryState {
159159
}
160160

161161
export type DataFrameAnalyticsUrlState = MLPageState<
162-
typeof ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE,
162+
typeof ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE | typeof ML_PAGES.DATA_FRAME_ANALYTICS_MAP,
163163
DataFrameAnalyticsQueryState | undefined
164164
>;
165165

x-pack/plugins/ml/common/util/analytics_utils.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
OutlierAnalysis,
1111
RegressionAnalysis,
1212
} from '../types/data_frame_analytics';
13-
import { ANALYSIS_CONFIG_TYPE } from '../../common/constants/data_frame_analytics';
13+
import { ANALYSIS_CONFIG_TYPE } from '../constants/data_frame_analytics';
14+
import { DataFrameAnalysisConfigType } from '../types/data_frame_analytics';
1415

1516
export const isOutlierAnalysis = (arg: any): arg is OutlierAnalysis => {
1617
if (typeof arg !== 'object' || arg === null) return false;
@@ -80,3 +81,15 @@ export const getPredictedFieldName = (
8081
}`;
8182
return predictedField;
8283
};
84+
85+
export const getAnalysisType = (
86+
analysis: AnalysisConfig
87+
): DataFrameAnalysisConfigType | 'unknown' => {
88+
const keys = Object.keys(analysis || {});
89+
90+
if (keys.length === 1) {
91+
return keys[0] as DataFrameAnalysisConfigType;
92+
}
93+
94+
return 'unknown';
95+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import 'pages/analytics_exploration/components/regression_exploration/index';
2+
@import 'pages/job_map/components/index';
23
@import 'pages/analytics_management/components/analytics_list/index';
34
@import 'pages/analytics_management/components/create_analytics_button/index';
45
@import 'pages/analytics_creation/components/index';

x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import {
2727
getPredictedFieldName,
2828
} from '../../../../common/util/analytics_utils';
2929
import { ANALYSIS_CONFIG_TYPE } from '../../../../common/constants/data_frame_analytics';
30+
31+
export { getAnalysisType } from '../../../../common/util/analytics_utils';
3032
export type IndexPattern = string;
3133

3234
export enum ANALYSIS_ADVANCED_FIELDS {
@@ -159,18 +161,6 @@ interface LoadEvaluateResult {
159161
error: string | null;
160162
}
161163

162-
export const getAnalysisType = (
163-
analysis: AnalysisConfig
164-
): DataFrameAnalysisConfigType | 'unknown' => {
165-
const keys = Object.keys(analysis);
166-
167-
if (keys.length === 1) {
168-
return keys[0] as DataFrameAnalysisConfigType;
169-
}
170-
171-
return 'unknown';
172-
};
173-
174164
export const getTrainingPercent = (
175165
analysis: AnalysisConfig
176166
):
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
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+
export { MapButton } from './map_button';
8+
export { useMapAction } from './use_map_action';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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 React, { FC } from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { EuiToolTip } from '@elastic/eui';
10+
11+
import {
12+
isRegressionAnalysis,
13+
isOutlierAnalysis,
14+
isClassificationAnalysis,
15+
} from '../../../../common/analytics';
16+
17+
import { DataFrameAnalyticsListRow } from '../analytics_list/common';
18+
19+
export const mapActionButtonText = i18n.translate(
20+
'xpack.ml.dataframe.analyticsList.mapActionName',
21+
{
22+
defaultMessage: 'Map',
23+
}
24+
);
25+
interface MapButtonProps {
26+
item: DataFrameAnalyticsListRow;
27+
}
28+
29+
export const MapButton: FC<MapButtonProps> = ({ item }) => {
30+
const disabled =
31+
!isRegressionAnalysis(item.config.analysis) &&
32+
!isOutlierAnalysis(item.config.analysis) &&
33+
!isClassificationAnalysis(item.config.analysis);
34+
35+
if (disabled) {
36+
const toolTipContent = i18n.translate(
37+
'xpack.ml.dataframe.analyticsList.mapActionDisabledTooltipContent',
38+
{
39+
defaultMessage: 'Unknown analysis type.',
40+
}
41+
);
42+
43+
return (
44+
<EuiToolTip position="top" content={toolTipContent}>
45+
<>{mapActionButtonText}</>
46+
</EuiToolTip>
47+
);
48+
}
49+
50+
return <>{mapActionButtonText}</>;
51+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 React, { useCallback, useMemo } from 'react';
8+
import { useMlUrlGenerator, useNavigateToPath } from '../../../../../contexts/kibana';
9+
import { DataFrameAnalyticsListAction, DataFrameAnalyticsListRow } from '../analytics_list/common';
10+
import { ML_PAGES } from '../../../../../../../common/constants/ml_url_generator';
11+
import { getViewLinkStatus } from '../action_view/get_view_link_status';
12+
13+
import { mapActionButtonText, MapButton } from './map_button';
14+
15+
export type MapAction = ReturnType<typeof useMapAction>;
16+
export const useMapAction = () => {
17+
const mlUrlGenerator = useMlUrlGenerator();
18+
const navigateToPath = useNavigateToPath();
19+
20+
const clickHandler = useCallback(async (item: DataFrameAnalyticsListRow) => {
21+
const path = await mlUrlGenerator.createUrl({
22+
page: ML_PAGES.DATA_FRAME_ANALYTICS_MAP,
23+
pageState: { jobId: item.id },
24+
});
25+
26+
await navigateToPath(path, false);
27+
}, []);
28+
29+
const action: DataFrameAnalyticsListAction = useMemo(
30+
() => ({
31+
isPrimary: true,
32+
name: (item: DataFrameAnalyticsListRow) => <MapButton item={item} />,
33+
enabled: (item: DataFrameAnalyticsListRow) => !getViewLinkStatus(item).disabled,
34+
description: mapActionButtonText,
35+
icon: 'graphApp',
36+
type: 'icon',
37+
onClick: clickHandler,
38+
'data-test-subj': 'mlAnalyticsJobMapButton',
39+
}),
40+
[clickHandler]
41+
);
42+
43+
return { action };
44+
};

x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_actions.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { isEditActionFlyoutVisible, useEditAction, EditActionFlyout } from '../a
1616
import { useStartAction, StartActionModal } from '../action_start';
1717
import { useStopAction, StopActionModal } from '../action_stop';
1818
import { useViewAction } from '../action_view';
19+
import { useMapAction } from '../action_map';
1920

2021
import { DataFrameAnalyticsListRow } from './common';
2122

@@ -30,6 +31,7 @@ export const useActions = (
3031
const canStartStopDataFrameAnalytics: boolean = checkPermission('canStartStopDataFrameAnalytics');
3132

3233
const viewAction = useViewAction();
34+
const mapAction = useMapAction();
3335
const cloneAction = useCloneAction(canCreateDataFrameAnalytics);
3436
const deleteAction = useDeleteAction(canDeleteDataFrameAnalytics);
3537
const editAction = useEditAction(canStartStopDataFrameAnalytics);
@@ -40,6 +42,7 @@ export const useActions = (
4042

4143
const actions: EuiTableActionsColumnType<DataFrameAnalyticsListRow>['actions'] = [
4244
viewAction.action,
45+
mapAction.action,
4346
];
4447

4548
// isManagementTable will be the same for the lifecycle of the component

0 commit comments

Comments
 (0)