Skip to content

Commit 2643c14

Browse files
committed
add MDS support for detector creation&Update flow (#728)
* update snapshots Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add snpshot Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add data source client Signed-off-by: Jackie Han <jkhanjob@gmail.com> * test * neo List Detectors page Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add opensearch_dashboards.json file Signed-off-by: Jackie Han <jkhanjob@gmail.com> * neo List Detectors page Signed-off-by: Jackie Han <jkhanjob@gmail.com> * test Signed-off-by: Jackie Han <jkhanjob@gmail.com> * Support MDS on DetectorDetails page Signed-off-by: Jackie Han <jkhanjob@gmail.com> * change 4/7 Signed-off-by: Jackie Han <jkhanjob@gmail.com> * version change Signed-off-by: Jackie Han <jkhanjob@gmail.com> * list detector list change Signed-off-by: Jackie Han <jkhanjob@gmail.com> * Support MDS on List, Detail, Dashboard, Overview pages Signed-off-by: Jackie Han <jkhanjob@gmail.com> * change version back to 3.0 Signed-off-by: Jackie Han <jkhanjob@gmail.com> * revert version change Signed-off-by: Jackie Han <jkhanjob@gmail.com> * make dataSourceId optional in DetectorListItem type Signed-off-by: Jackie Han <jkhanjob@gmail.com> * update imports Signed-off-by: Jackie Han <jkhanjob@gmail.com> * remove used function Signed-off-by: Jackie Han <jkhanjob@gmail.com> * cleanup Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add getter and setter for dataSource plugin Signed-off-by: Jackie Han <jkhanjob@gmail.com> * read dataSourceId from the url instead of passing props Signed-off-by: Jackie Han <jkhanjob@gmail.com> * addressing comments Signed-off-by: Jackie Han <jkhanjob@gmail.com> * addressing comments and run prettier Signed-off-by: Jackie Han <jkhanjob@gmail.com> * addressing comments in neo1 branch Signed-off-by: Jackie Han <jkhanjob@gmail.com> * addressing comments Signed-off-by: Jackie Han <jkhanjob@gmail.com> * make getDataSourceManagementPlugin() optional Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add comment Signed-off-by: Jackie Han <jkhanjob@gmail.com> * make dataSourceId type safe Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add MDS support on creation page Signed-off-by: Jackie Han <jkhanjob@gmail.com> * updated methods to get data source query param from url Signed-off-by: Jackie Han <jkhanjob@gmail.com> * using helper to construct url with dataSourceId Signed-off-by: Jackie Han <jkhanjob@gmail.com> * add update page, and update urls on detector detail page Signed-off-by: Jackie Han <jkhanjob@gmail.com> * update update call router Signed-off-by: Jackie Han <jkhanjob@gmail.com> * update reducer and router Signed-off-by: Jackie Han <jkhanjob@gmail.com> * clean up Signed-off-by: Jackie Han <jkhanjob@gmail.com> * addressing comments Signed-off-by: Jackie Han <jkhanjob@gmail.com> * update enums Signed-off-by: Jackie Han <jkhanjob@gmail.com> --------- Signed-off-by: Jackie Han <jkhanjob@gmail.com>
1 parent 4ea8698 commit 2643c14

File tree

37 files changed

+680
-237
lines changed

37 files changed

+680
-237
lines changed

public/components/CreateDetectorButtons/CreateDetectorButtons.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,24 @@
1212
import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui';
1313
import React from 'react';
1414
import { APP_PATH, PLUGIN_NAME } from '../../utils/constants';
15+
import { useLocation } from 'react-router-dom';
16+
import { constructHrefWithDataSourceId, getDataSourceFromURL } from '../../pages/utils/helpers';
1517

1618
export const CreateDetectorButtons = () => {
19+
const location = useLocation();
20+
const MDSQueryParams = getDataSourceFromURL(location);
21+
const dataSourceId = MDSQueryParams.dataSourceId;
22+
23+
const createDetectorUrl = `${PLUGIN_NAME}#` + constructHrefWithDataSourceId(`${APP_PATH.CREATE_DETECTOR}`, dataSourceId, false);
24+
25+
const sampleDetectorUrl = `${PLUGIN_NAME}#` + constructHrefWithDataSourceId(`${APP_PATH.OVERVIEW}`, dataSourceId, false);
26+
1727
return (
1828
<EuiFlexGroup direction="row" gutterSize="m" justifyContent="center">
1929
<EuiFlexItem grow={false}>
2030
<EuiButton
2131
style={{ width: '200px' }}
22-
href={`${PLUGIN_NAME}#${APP_PATH.OVERVIEW}`}
32+
href={sampleDetectorUrl}
2333
data-test-subj="sampleDetectorButton"
2434
>
2535
Try a sample detector
@@ -29,7 +39,7 @@ export const CreateDetectorButtons = () => {
2939
<EuiButton
3040
style={{ width: '200px' }}
3141
fill
32-
href={`${PLUGIN_NAME}#${APP_PATH.CREATE_DETECTOR}`}
42+
href={createDetectorUrl}
3343
data-test-subj="createDetectorButton"
3444
>
3545
Create detector

public/models/interfaces.ts

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { DATA_TYPES } from '../utils/constants';
1414
import { DETECTOR_STATE } from '../../server/utils/constants';
1515
import { Duration } from 'moment';
1616
import moment from 'moment';
17+
import { MDSQueryParams } from '../../server/models/types';
1718

1819
export type FieldInfo = {
1920
label: string;
@@ -326,3 +327,8 @@ export interface ValidationSettingResponse {
326327
message: string;
327328
validationType: string;
328329
}
330+
331+
export interface MDSStates {
332+
queryParams: MDSQueryParams;
333+
selectedDataSourceId: string;
334+
}

public/pages/AnomalyCharts/containers/AnomalyDetailsChart.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import {
9393
} from '../../../../server/utils/constants';
9494
import { ENTITY_COLORS } from '../../DetectorResults/utils/constants';
9595
import { useLocation } from 'react-router-dom';
96+
import { getDataSourceFromURL } from '../../../pages/utils/helpers';
9697

9798
interface AnomalyDetailsChartProps {
9899
onDateRangeChange(
@@ -123,8 +124,8 @@ export const AnomalyDetailsChart = React.memo(
123124
(props: AnomalyDetailsChartProps) => {
124125
const dispatch = useDispatch();
125126
const location = useLocation();
126-
const dataSourceId =
127-
new URLSearchParams(location.search).get(DATA_SOURCE_ID) || '';
127+
const MDSQueryParams = getDataSourceFromURL(location);
128+
const dataSourceId = MDSQueryParams.dataSourceId;
128129
const [showAlertsFlyout, setShowAlertsFlyout] = useState<boolean>(false);
129130
const [alertAnnotations, setAlertAnnotations] = useState<any[]>([]);
130131
const [isLoadingAlerts, setIsLoadingAlerts] = useState<boolean>(false);
@@ -331,7 +332,7 @@ export const AnomalyDetailsChart = React.memo(
331332
try {
332333
setIsLoadingAlerts(true);
333334
const result = await dispatch(
334-
searchAlerts(monitorId, startDateTime, endDateTime)
335+
searchAlerts(monitorId, startDateTime, endDateTime, dataSourceId)
335336
);
336337
setIsLoadingAlerts(false);
337338
setTotalAlerts(get(result, 'response.totalAlerts'));

public/pages/ConfigureModel/containers/ConfigureModel.tsx

+65-11
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ import {
2626
} from '@elastic/eui';
2727
import { FormikProps, Formik } from 'formik';
2828
import { get, isEmpty } from 'lodash';
29-
import React, { Fragment, useState, useEffect } from 'react';
29+
import React, { Fragment, useState, useEffect, ReactElement } from 'react';
3030
import { useDispatch, useSelector } from 'react-redux';
31-
import { RouteComponentProps } from 'react-router-dom';
31+
import { RouteComponentProps, useLocation } from 'react-router-dom';
3232
import { AppState } from '../../../redux/reducers';
3333
import { getMappings } from '../../../redux/reducers/opensearch';
3434
import { useFetchDetectorInfo } from '../../CreateDetectorSteps/hooks/useFetchDetectorInfo';
@@ -49,7 +49,7 @@ import { Features } from '../components/Features';
4949
import { CategoryField } from '../components/CategoryField';
5050
import { AdvancedSettings } from '../components/AdvancedSettings';
5151
import { SampleAnomalies } from './SampleAnomalies';
52-
import { CoreStart } from '../../../../../../src/core/public';
52+
import { CoreStart, MountPoint } from '../../../../../../src/core/public';
5353
import { CoreServicesContext } from '../../../components/CoreServices/CoreServices';
5454
import { Detector } from '../../../models/interfaces';
5555
import { prettifyErrorMessage } from '../../../../server/utils/helpers';
@@ -58,6 +58,17 @@ import { ModelConfigurationFormikValues } from '../models/interfaces';
5858
import { CreateDetectorFormikValues } from '../../CreateDetectorSteps/models/interfaces';
5959
import { DETECTOR_STATE } from '../../../../server/utils/constants';
6060
import { getErrorMessage } from '../../../utils/utils';
61+
import {
62+
constructHrefWithDataSourceId,
63+
getDataSourceFromURL,
64+
} from '../../../pages/utils/helpers';
65+
import {
66+
getDataSourceManagementPlugin,
67+
getDataSourcePlugin,
68+
getNotifications,
69+
getSavedObjectsClient,
70+
} from '../../../services';
71+
import { DataSourceViewConfig } from '../../../../../../src/plugins/data_source_management/public';
6172

6273
interface ConfigureModelRouterProps {
6374
detectorId?: string;
@@ -70,14 +81,20 @@ interface ConfigureModelProps
7081
initialValues?: ModelConfigurationFormikValues;
7182
setInitialValues?(initialValues: ModelConfigurationFormikValues): void;
7283
detectorDefinitionValues?: DetectorDefinitionFormikValues;
84+
setActionMenu: (menuMount: MountPoint | undefined) => void;
7385
}
7486

7587
export function ConfigureModel(props: ConfigureModelProps) {
7688
const core = React.useContext(CoreServicesContext) as CoreStart;
7789
const dispatch = useDispatch();
90+
const location = useLocation();
91+
const MDSQueryParams = getDataSourceFromURL(location);
92+
const dataSourceEnabled = getDataSourcePlugin()?.dataSourceEnabled || false;
93+
const dataSourceId = MDSQueryParams.dataSourceId;
94+
7895
useHideSideNavBar(true, false);
7996
const detectorId = get(props, 'match.params.detectorId', '');
80-
const { detector, hasError } = useFetchDetectorInfo(detectorId);
97+
const { detector, hasError } = useFetchDetectorInfo(detectorId, dataSourceId);
8198
const indexDataTypes = useSelector(
8299
(state: AppState) => state.opensearch.dataTypes
83100
);
@@ -100,7 +117,7 @@ export function ConfigureModel(props: ConfigureModelProps) {
100117
setIsHCDetector(true);
101118
}
102119
if (detector?.indices) {
103-
dispatch(getMappings(detector.indices[0]));
120+
dispatch(getMappings(detector.indices[0], dataSourceId));
104121
}
105122
}, [detector]);
106123

@@ -111,7 +128,7 @@ export function ConfigureModel(props: ConfigureModelProps) {
111128
BREADCRUMBS.DETECTORS,
112129
{
113130
text: detector && detector.name ? detector.name : '',
114-
href: `#/detectors/${detectorId}`,
131+
href: constructHrefWithDataSourceId(`#/detectors/${detectorId}`, dataSourceId, false)
115132
},
116133
BREADCRUMBS.EDIT_MODEL_CONFIGURATION,
117134
]);
@@ -126,7 +143,9 @@ export function ConfigureModel(props: ConfigureModelProps) {
126143

127144
useEffect(() => {
128145
if (hasError) {
129-
props.history.push('/detectors');
146+
props.history.push(
147+
constructHrefWithDataSourceId('/detectors', dataSourceId, false)
148+
);
130149
}
131150
}, [hasError]);
132151

@@ -178,12 +197,18 @@ export function ConfigureModel(props: ConfigureModelProps) {
178197
};
179198

180199
const handleUpdateDetector = async (detectorToUpdate: Detector) => {
181-
dispatch(updateDetector(detectorId, detectorToUpdate))
200+
dispatch(updateDetector(detectorId, detectorToUpdate, dataSourceId))
182201
.then((response: any) => {
183202
core.notifications.toasts.addSuccess(
184203
`Detector updated: ${response.response.name}`
185204
);
186-
props.history.push(`/detectors/${detectorId}/configurations/`);
205+
props.history.push(
206+
constructHrefWithDataSourceId(
207+
`/detectors/${detectorId}/configurations/`,
208+
dataSourceId,
209+
false
210+
)
211+
);
187212
})
188213
.catch((err: any) => {
189214
core.notifications.toasts.addDanger(
@@ -207,6 +232,24 @@ export function ConfigureModel(props: ConfigureModelProps) {
207232
...props.initialValues,
208233
} as CreateDetectorFormikValues);
209234

235+
let renderDataSourceComponent: ReactElement | null = null;
236+
if (dataSourceEnabled) {
237+
const DataSourceMenu =
238+
getDataSourceManagementPlugin()?.ui.getDataSourceMenu<DataSourceViewConfig>();
239+
renderDataSourceComponent = (
240+
<DataSourceMenu
241+
setMenuMountPoint={props.setActionMenu}
242+
componentType={'DataSourceView'}
243+
componentConfig={{
244+
activeOption: [{ id: dataSourceId }],
245+
fullWidth: false,
246+
savedObjects: getSavedObjectsClient(),
247+
notifications: getNotifications(),
248+
}}
249+
/>
250+
);
251+
}
252+
210253
return (
211254
<Formik
212255
initialValues={
@@ -221,6 +264,7 @@ export function ConfigureModel(props: ConfigureModelProps) {
221264
>
222265
{(formikProps) => (
223266
<Fragment>
267+
{dataSourceEnabled && renderDataSourceComponent}
224268
<EuiPage
225269
style={{
226270
marginTop: '-24px',
@@ -293,10 +337,20 @@ export function ConfigureModel(props: ConfigureModelProps) {
293337
onClick={() => {
294338
if (props.isEdit) {
295339
props.history.push(
296-
`/detectors/${detectorId}/configurations/`
340+
constructHrefWithDataSourceId(
341+
`/detectors/${detectorId}/configurations/`,
342+
dataSourceId,
343+
false
344+
)
297345
);
298346
} else {
299-
props.history.push('/detectors');
347+
props.history.push(
348+
constructHrefWithDataSourceId(
349+
'/detectors',
350+
dataSourceId,
351+
false
352+
)
353+
);
300354
}
301355
}}
302356
>

public/pages/ConfigureModel/containers/SampleAnomalies.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ import { BASE_DOCS_LINK } from '../../../utils/constants';
4949
import { prettifyErrorMessage } from '../../../../server/utils/helpers';
5050
import { CoreStart } from '../../../../../../src/core/public';
5151
import { CoreServicesContext } from '../../../components/CoreServices/CoreServices';
52+
import { useLocation } from 'react-router-dom';
53+
import { getDataSourceFromURL } from '../../../pages/utils/helpers';
5254

5355
interface SampleAnomaliesProps {
5456
detector: Detector;
@@ -62,6 +64,9 @@ interface SampleAnomaliesProps {
6264
export function SampleAnomalies(props: SampleAnomaliesProps) {
6365
const core = React.useContext(CoreServicesContext) as CoreStart;
6466
const dispatch = useDispatch();
67+
const location = useLocation();
68+
const MDSQueryParams = getDataSourceFromURL(location);
69+
const dataSourceId = MDSQueryParams.dataSourceId;
6570
useHideSideNavBar(true, false);
6671

6772
const [isLoading, setIsLoading] = useState<boolean>(false);
@@ -150,6 +155,7 @@ export function SampleAnomalies(props: SampleAnomaliesProps) {
150155
periodStart: dateRange.startDate.valueOf(),
151156
periodEnd: dateRange.endDate.valueOf(),
152157
detector: detector,
158+
dataSourceId: dataSourceId,
153159
})
154160
);
155161
setIsLoading(false);

public/pages/CreateDetectorSteps/containers/CreateDetectorSteps.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ import { DetectorDefinitionFormikValues } from '../../DefineDetector/models/inte
2525
import { ModelConfigurationFormikValues } from '../../ConfigureModel/models/interfaces';
2626
import { DetectorJobsFormikValues } from '../../DetectorJobs/models/interfaces';
2727
import { CreateDetectorFormikValues } from '../models/interfaces';
28+
import { MountPoint } from '../../../../../../src/core/public';
2829

29-
interface CreateDetectorStepsProps extends RouteComponentProps {}
30+
interface CreateDetectorStepsProps extends RouteComponentProps {
31+
setActionMenu: (menuMount: MountPoint | undefined) => void;
32+
}
3033

3134
export const CreateDetectorSteps = (props: CreateDetectorStepsProps) => {
3235
useHideSideNavBar(true, false);

public/pages/CreateDetectorSteps/hooks/useFetchDetectorInfo.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,10 @@ export const useFetchDetectorInfo = (
4444
useEffect(() => {
4545
const fetchDetector = async () => {
4646
if (!detector) {
47-
// hardcoding the datasource id for now, will update it later when working on create page
4847
await dispatch(getDetector(detectorId, dataSourceId));
4948
}
5049
if (selectedIndices) {
51-
await dispatch(getMappings(selectedIndices));
50+
await dispatch(getMappings(selectedIndices, dataSourceId));
5251
}
5352
};
5453
if (detectorId) {

public/pages/Dashboard/Components/AnomaliesDistribution.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { AD_DOC_FIELDS } from '../../../../server/utils/constants';
3434
import { ALL_CUSTOM_AD_RESULT_INDICES } from '../../utils/constants';
3535
import { searchResults } from '../../../redux/reducers/anomalyResults';
3636
import { useLocation } from 'react-router-dom';
37-
import { DATA_SOURCE_ID } from '../../../utils/constants';
37+
import { getDataSourceFromURL } from '../../../pages/utils/helpers';
3838
export interface AnomaliesDistributionChartProps {
3939
selectedDetectors: DetectorListItem[];
4040
}
@@ -44,8 +44,8 @@ export const AnomaliesDistributionChart = (
4444
) => {
4545
const dispatch = useDispatch();
4646
const location = useLocation();
47-
const dataSourceId =
48-
new URLSearchParams(location.search).get(DATA_SOURCE_ID) || '';
47+
const MDSQueryParams = getDataSourceFromURL(location);
48+
const dataSourceId = MDSQueryParams.dataSourceId;
4949

5050
const [anomalyDistribution, setAnomalyDistribution] = useState(
5151
[] as object[]

public/pages/Dashboard/Components/AnomaliesLiveChart.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import {
5959
import { ALL_CUSTOM_AD_RESULT_INDICES } from '../../utils/constants';
6060
import { searchResults } from '../../../redux/reducers/anomalyResults';
6161
import { useLocation } from 'react-router-dom';
62+
import { getDataSourceFromURL } from '../../../pages/utils/helpers';
6263

6364
export interface AnomaliesLiveChartProps {
6465
selectedDetectors: DetectorListItem[];
@@ -74,9 +75,8 @@ const MAX_LIVE_DETECTORS = 10;
7475
export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => {
7576
const dispatch = useDispatch();
7677
const location = useLocation();
77-
const dataSourceId =
78-
new URLSearchParams(location.search).get(DATA_SOURCE_ID) || '';
79-
78+
const MDSQueryParams = getDataSourceFromURL(location);
79+
const dataSourceId = MDSQueryParams.dataSourceId;
8080
const [liveTimeRange, setLiveTimeRange] = useState<LiveTimeRangeState>({
8181
startDateTime: moment().subtract(31, 'minutes'),
8282
endDateTime: moment(),

public/pages/Dashboard/Components/utils/DashboardHeader.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,22 @@ import {
1717
EuiPageHeader,
1818
EuiTitle,
1919
} from '@elastic/eui';
20-
import { PLUGIN_NAME, APP_PATH } from '../../../../utils/constants';
20+
import {
21+
PLUGIN_NAME,
22+
APP_PATH,
23+
} from '../../../../utils/constants';
24+
import { useLocation } from 'react-router-dom';
25+
import { constructHrefWithDataSourceId, getDataSourceFromURL } from '../../../../pages/utils/helpers';
2126
export interface DashboardHeaderProps {
2227
hasDetectors: boolean;
2328
}
2429

2530
export const DashboardHeader = (props: DashboardHeaderProps) => {
31+
const location = useLocation();
32+
const MDSQueryParams = getDataSourceFromURL(location);
33+
const dataSourceId = MDSQueryParams.dataSourceId;
34+
const createDetectorUrl = `${PLUGIN_NAME}#` + constructHrefWithDataSourceId(APP_PATH.CREATE_DETECTOR, dataSourceId, false);
35+
2636
return (
2737
<EuiPageHeader>
2838
<EuiFlexGroup justifyContent="spaceBetween">
@@ -35,7 +45,7 @@ export const DashboardHeader = (props: DashboardHeaderProps) => {
3545
<EuiFlexItem grow={false}>
3646
<EuiButton
3747
fill
38-
href={`${PLUGIN_NAME}#${APP_PATH.CREATE_DETECTOR}`}
48+
href={createDetectorUrl}
3949
data-test-subj="add_detector"
4050
>
4151
Create detector

0 commit comments

Comments
 (0)