Skip to content

Commit

Permalink
Support MDS on List, Detail, Dashboard, Overview pages (#722)
Browse files Browse the repository at this point in the history
* update snapshots

Signed-off-by: Jackie Han <[email protected]>

* add snpshot

Signed-off-by: Jackie Han <[email protected]>

* add data source client

Signed-off-by: Jackie Han <[email protected]>

* test

* neo List Detectors page

Signed-off-by: Jackie Han <[email protected]>

* add opensearch_dashboards.json file

Signed-off-by: Jackie Han <[email protected]>

* neo List Detectors page

Signed-off-by: Jackie Han <[email protected]>

* test

Signed-off-by: Jackie Han <[email protected]>

* Support MDS on DetectorDetails page

Signed-off-by: Jackie Han <[email protected]>

* change 4/7

Signed-off-by: Jackie Han <[email protected]>

* version change

Signed-off-by: Jackie Han <[email protected]>

* list detector list change

Signed-off-by: Jackie Han <[email protected]>

* Support MDS on List, Detail, Dashboard, Overview pages

Signed-off-by: Jackie Han <[email protected]>

* change version back to 3.0

Signed-off-by: Jackie Han <[email protected]>

* revert version change

Signed-off-by: Jackie Han <[email protected]>

* make dataSourceId optional in DetectorListItem type

Signed-off-by: Jackie Han <[email protected]>

* update imports

Signed-off-by: Jackie Han <[email protected]>

* remove used function

Signed-off-by: Jackie Han <[email protected]>

* cleanup

Signed-off-by: Jackie Han <[email protected]>

* add getter and setter for dataSource plugin

Signed-off-by: Jackie Han <[email protected]>

* read dataSourceId from the url instead of passing props

Signed-off-by: Jackie Han <[email protected]>

* addressing comments and run prettier

Signed-off-by: Jackie Han <[email protected]>

* addressing comments

Signed-off-by: Jackie Han <[email protected]>

* make getDataSourceManagementPlugin() optional

Signed-off-by: Jackie Han <[email protected]>

* add comment

Signed-off-by: Jackie Han <[email protected]>

* make dataSourceId type safe

Signed-off-by: Jackie Han <[email protected]>

---------

Signed-off-by: Jackie Han <[email protected]>
(cherry picked from commit ee5504f)
  • Loading branch information
jackiehanyang authored and github-actions[bot] committed Apr 18, 2024
1 parent 437b0ed commit 0942c6e
Show file tree
Hide file tree
Showing 43 changed files with 1,447 additions and 561 deletions.
1 change: 1 addition & 0 deletions opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"configPath": [
"anomaly_detection_dashboards"
],
"optionalPlugins": ["dataSource","dataSourceManagement"],
"requiredPlugins": [
"opensearchDashboardsUtils",
"expressions",
Expand Down
6 changes: 5 additions & 1 deletion public/anomaly_detection_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ export function renderApp(coreStart: CoreStart, params: AppMountParameters) {
} else {
require('@elastic/charts/dist/theme_only_light.css');
}

ReactDOM.render(
<Provider store={store}>
<Router>
<Route
render={(props) => (
<CoreServicesContext.Provider value={coreStart}>
<Main {...props} />
<Main
setHeaderActionMenu={params.setHeaderActionMenu}
{...props}
/>
</CoreServicesContext.Provider>
)}
/>
Expand Down
21 changes: 17 additions & 4 deletions public/pages/AnomalyCharts/containers/AnomalyDetailsChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,18 @@ import {
} from '../utils/constants';
import { HeatmapCell } from './AnomalyHeatmapChart';
import { ANOMALY_AGG, MIN_END_TIME, MAX_END_TIME } from '../../utils/constants';
import { MAX_HISTORICAL_AGG_RESULTS } from '../../../utils/constants';
import {
DATA_SOURCE_ID,
MAX_HISTORICAL_AGG_RESULTS,
} from '../../../utils/constants';
import { searchResults } from '../../../redux/reducers/anomalyResults';
import {
DAY_IN_MILLI_SECS,
WEEK_IN_MILLI_SECS,
DETECTOR_STATE,
} from '../../../../server/utils/constants';
import { ENTITY_COLORS } from '../../DetectorResults/utils/constants';
import { useLocation } from 'react-router-dom';

interface AnomalyDetailsChartProps {
onDateRangeChange(
Expand Down Expand Up @@ -118,6 +122,9 @@ interface AnomalyDetailsChartProps {
export const AnomalyDetailsChart = React.memo(
(props: AnomalyDetailsChartProps) => {
const dispatch = useDispatch();
const location = useLocation();
const dataSourceId =
new URLSearchParams(location.search).get(DATA_SOURCE_ID) || '';
const [showAlertsFlyout, setShowAlertsFlyout] = useState<boolean>(false);
const [alertAnnotations, setAlertAnnotations] = useState<any[]>([]);
const [isLoadingAlerts, setIsLoadingAlerts] = useState<boolean>(false);
Expand Down Expand Up @@ -174,7 +181,9 @@ export const AnomalyDetailsChart = React.memo(
zoomRange.endDate,
taskId
);
dispatch(searchResults(anomalyDataRangeQuery, resultIndex, true))
dispatch(
searchResults(anomalyDataRangeQuery, resultIndex, dataSourceId, true)
)
.then((response: any) => {
// Only retrieve buckets that are in the anomaly results range. This is so
// we don't show aggregate results for where there is no data at all
Expand All @@ -193,7 +202,9 @@ export const AnomalyDetailsChart = React.memo(
taskId,
selectedAggId
);
dispatch(searchResults(historicalAggQuery, resultIndex, true))
dispatch(
searchResults(historicalAggQuery, resultIndex, dataSourceId, true)
)
.then((response: any) => {
const aggregatedAnomalies = parseHistoricalAggregatedAnomalies(
response,
Expand Down Expand Up @@ -229,7 +240,9 @@ export const AnomalyDetailsChart = React.memo(
zoomRange.endDate,
taskId
);
dispatch(searchResults(anomalyDataRangeQuery, resultIndex, true))
dispatch(
searchResults(anomalyDataRangeQuery, resultIndex, dataSourceId, true)
)
.then((response: any) => {
const dataStartDate = get(
response,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import { getMappings } from '../../../redux/reducers/opensearch';
// 1. Get detector
// 2. Gets index mapping
export const useFetchDetectorInfo = (
detectorId: string
detectorId: string,
dataSourceId: string
): {
detector: Detector;
hasError: boolean;
Expand All @@ -43,7 +44,8 @@ export const useFetchDetectorInfo = (
useEffect(() => {
const fetchDetector = async () => {
if (!detector) {
await dispatch(getDetector(detectorId));
// hardcoding the datasource id for now, will update it later when working on create page
await dispatch(getDetector(detectorId, dataSourceId));
}
if (selectedIndices) {
await dispatch(getMappings(selectedIndices));
Expand Down
6 changes: 6 additions & 0 deletions public/pages/Dashboard/Components/AnomaliesDistribution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import { get, isEmpty } from 'lodash';
import { AD_DOC_FIELDS } from '../../../../server/utils/constants';
import { ALL_CUSTOM_AD_RESULT_INDICES } from '../../utils/constants';
import { searchResults } from '../../../redux/reducers/anomalyResults';
import { useLocation } from 'react-router-dom';
import { DATA_SOURCE_ID } from '../../../utils/constants';
export interface AnomaliesDistributionChartProps {
selectedDetectors: DetectorListItem[];
}
Expand All @@ -41,6 +43,9 @@ export const AnomaliesDistributionChart = (
props: AnomaliesDistributionChartProps
) => {
const dispatch = useDispatch();
const location = useLocation();
const dataSourceId =
new URLSearchParams(location.search).get(DATA_SOURCE_ID) || '';

const [anomalyDistribution, setAnomalyDistribution] = useState(
[] as object[]
Expand All @@ -66,6 +71,7 @@ export const AnomaliesDistributionChart = (
await getAnomalyDistributionForDetectorsByTimeRange(
searchResults,
props.selectedDetectors,
dataSourceId,
timeRange,
dispatch,
0,
Expand Down
16 changes: 13 additions & 3 deletions public/pages/Dashboard/Components/AnomaliesLiveChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,14 @@ import {
getLatestAnomalyResultsForDetectorsByTimeRange,
getLatestAnomalyResultsByTimeRange,
} from '../utils/utils';
import { MAX_ANOMALIES, SPACE_STR } from '../../../utils/constants';
import {
DATA_SOURCE_ID,
MAX_ANOMALIES,
SPACE_STR,
} from '../../../utils/constants';
import { ALL_CUSTOM_AD_RESULT_INDICES } from '../../utils/constants';
import { searchResults } from '../../../redux/reducers/anomalyResults';
import { useLocation } from 'react-router-dom';

export interface AnomaliesLiveChartProps {
selectedDetectors: DetectorListItem[];
Expand All @@ -68,6 +73,9 @@ const MAX_LIVE_DETECTORS = 10;

export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => {
const dispatch = useDispatch();
const location = useLocation();
const dataSourceId =
new URLSearchParams(location.search).get(DATA_SOURCE_ID) || '';

const [liveTimeRange, setLiveTimeRange] = useState<LiveTimeRangeState>({
startDateTime: moment().subtract(31, 'minutes'),
Expand Down Expand Up @@ -102,7 +110,8 @@ export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => {
1,
true,
ALL_CUSTOM_AD_RESULT_INDICES,
false
false,
dataSourceId
);
} catch (err) {
console.log(
Expand All @@ -126,7 +135,8 @@ export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => {
MAX_LIVE_DETECTORS,
false,
ALL_CUSTOM_AD_RESULT_INDICES,
false
false,
dataSourceId
);
setLiveAnomalyData(latestLiveAnomalyResult);

Expand Down
110 changes: 99 additions & 11 deletions public/pages/Dashboard/Container/DashboardOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
* GitHub history for details.
*/

import React, { Fragment, useState, useEffect } from 'react';
import React, { Fragment, useState, useEffect, useMemo } from 'react';
import { AnomaliesLiveChart } from '../Components/AnomaliesLiveChart';
import { AnomaliesDistributionChart } from '../Components/AnomaliesDistribution';
import queryString from 'querystring';

import { useDispatch, useSelector } from 'react-redux';
import { get, isEmpty, cloneDeep } from 'lodash';
Expand All @@ -29,27 +30,53 @@ import {
} from '@elastic/eui';
import { AnomalousDetectorsList } from '../Components/AnomalousDetectorsList';
import {
GET_ALL_DETECTORS_QUERY_PARAMS,
ALL_DETECTORS_MESSAGE,
ALL_DETECTOR_STATES_MESSAGE,
ALL_INDICES_MESSAGE,
} from '../utils/constants';
import { AppState } from '../../../redux/reducers';
import { CatIndex, IndexAlias } from '../../../../server/models/types';
import { getVisibleOptions } from '../../utils/helpers';
import {
CatIndex,
IndexAlias,
MDSQueryParams,
} from '../../../../server/models/types';
import {
getAllDetectorsQueryParamsWithDataSourceId,
getVisibleOptions,
} from '../../utils/helpers';
import { BREADCRUMBS } from '../../../utils/constants';
import { DETECTOR_STATE } from '../../../../server/utils/constants';
import { getDetectorStateOptions } from '../../DetectorsList/utils/helpers';
import {
getDetectorStateOptions,
getURLQueryParams,
} from '../../DetectorsList/utils/helpers';
import { DashboardHeader } from '../Components/utils/DashboardHeader';
import { EmptyDashboard } from '../Components/EmptyDashboard/EmptyDashboard';
import {
prettifyErrorMessage,
NO_PERMISSIONS_KEY_WORD,
} from '../../../../server/utils/helpers';
import { CoreServicesContext } from '../../../components/CoreServices/CoreServices';
import { CoreStart } from '../../../../../../src/core/public';
import { CoreStart, MountPoint } from '../../../../../../src/core/public';
import { DataSourceSelectableConfig } from '../../../../../../src/plugins/data_source_management/public';
import {
getDataSourceManagementPlugin,
getDataSourcePlugin,
getNotifications,
getSavedObjectsClient,
} from '../../../services';
import { RouteComponentProps } from 'react-router-dom';

interface OverviewProps extends RouteComponentProps {
setActionMenu: (menuMount: MountPoint | undefined) => void;
}

interface MDSOverviewState {
queryParams: MDSQueryParams;
selectedDataSourceId: string;
}

export function DashboardOverview() {
export function DashboardOverview(props: OverviewProps) {
const core = React.useContext(CoreServicesContext) as CoreStart;
const dispatch = useDispatch();
const adState = useSelector((state: AppState) => state.ad);
Expand All @@ -58,13 +85,23 @@ export function DashboardOverview() {
const errorGettingDetectors = adState.errorMessage;
const isLoadingDetectors = adState.requesting;

const dataSourceEnabled = getDataSourcePlugin()?.dataSourceEnabled || false;

const [currentDetectors, setCurrentDetectors] = useState(
Object.values(allDetectorList)
);
const [allDetectorsSelected, setAllDetectorsSelected] = useState(true);
const [selectedDetectorsName, setSelectedDetectorsName] = useState(
[] as string[]
);
const queryParams = getURLQueryParams(props.location);
const [MDSOverviewState, setMDSOverviewState] = useState<MDSOverviewState>({
queryParams,
selectedDataSourceId: queryParams.dataSourceId
? queryParams.dataSourceId
: '',
});

const getDetectorOptions = (detectorsIdMap: {
[key: string]: DetectorListItem;
}) => {
Expand Down Expand Up @@ -108,6 +145,20 @@ export function DashboardOverview() {
setAllDetectorStatesSelected(isEmpty(selectedStates));
};

const handleDataSourceChange = ([event]) => {
const dataSourceId = event?.id;
if (!dataSourceId) {
getNotifications().toasts.addDanger(
prettifyErrorMessage('Unable to set data source.')
);
} else {
setMDSOverviewState({
queryParams: dataSourceId,
selectedDataSourceId: dataSourceId,
});
}
};

const opensearchState = useSelector((state: AppState) => state.opensearch);

const [selectedIndices, setSelectedIndices] = useState([] as string[]);
Expand Down Expand Up @@ -157,14 +208,28 @@ export function DashboardOverview() {
};

const intializeDetectors = async () => {
dispatch(getDetectorList(GET_ALL_DETECTORS_QUERY_PARAMS));
dispatch(getIndices(''));
dispatch(getAliases(''));
dispatch(
getDetectorList(
getAllDetectorsQueryParamsWithDataSourceId(
MDSOverviewState.selectedDataSourceId
)
)
);
dispatch(getIndices('', MDSOverviewState.selectedDataSourceId));
dispatch(getAliases('', MDSOverviewState.selectedDataSourceId));
};

useEffect(() => {
const { history, location } = props;
const updatedParams = {
dataSourceId: MDSOverviewState.selectedDataSourceId,
};
history.replace({
...location,
search: queryString.stringify(updatedParams),
});
intializeDetectors();
}, []);
}, [MDSOverviewState]);

useEffect(() => {
if (errorGettingDetectors) {
Expand Down Expand Up @@ -197,9 +262,32 @@ export function DashboardOverview() {
);
}, [selectedDetectorsName, selectedIndices, selectedDetectorStates]);

let renderDataSourceComponent = null;
if (dataSourceEnabled) {
const DataSourceMenu =
getDataSourceManagementPlugin()?.ui.getDataSourceMenu<DataSourceSelectableConfig>();
renderDataSourceComponent = useMemo(() => {
return (
<DataSourceMenu
setMenuMountPoint={props.setActionMenu}
componentType={'DataSourceSelectable'}
componentConfig={{
fullWidth: false,
activeOption: [{ id: MDSOverviewState.selectedDataSourceId }],
savedObjects: getSavedObjectsClient(),
notifications: getNotifications(),
onSelectedDataSources: (dataSources) =>
handleDataSourceChange(dataSources),
}}
/>
);
}, [getSavedObjectsClient(), getNotifications(), props.setActionMenu]);
}

return (
<div style={{ height: '1200px' }}>
<Fragment>
{dataSourceEnabled && renderDataSourceComponent}
<DashboardHeader hasDetectors={totalRealtimeDetectors > 0} />
{isLoadingDetectors ? (
<div>
Expand Down
Loading

0 comments on commit 0942c6e

Please sign in to comment.