Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support MDS on ListDetectors page #716

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
17 changes: 15 additions & 2 deletions public/anomaly_detection_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ import { Main } from './pages/main';
import { Provider } from 'react-redux';
import configureStore from './redux/configureStore';
import { CoreServicesContext } from './components/CoreServices/CoreServices';
import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public';
import { DataSourcePluginSetup } from '../../../src/plugins/data_source/public';

export function renderApp(coreStart: CoreStart, params: AppMountParameters) {
export function renderApp(
coreStart: CoreStart,
params: AppMountParameters,
dataSourceManagement: DataSourceManagementPluginSetup,
dataSource: DataSourcePluginSetup
) {
const http = coreStart.http;
const store = configureStore(http);

Expand All @@ -29,13 +36,19 @@ 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
dataSourceEnabled={dataSource.dataSourceEnabled}
dataSourceManagement={dataSourceManagement}
setHeaderActionMenu={params.setHeaderActionMenu}
{...props}
/>
</CoreServicesContext.Provider>
)}
/>
Expand Down
1 change: 1 addition & 0 deletions public/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ export type DetectorListItem = {
lastUpdateTime: number;
enabledTime?: number;
detectorType?: string;
dataSourceId: string;
jackiehanyang marked this conversation as resolved.
Show resolved Hide resolved
};

export type EntityData = {
Expand Down
67 changes: 60 additions & 7 deletions public/pages/DetectorsList/containers/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
} from '@elastic/eui';
import { debounce, get, isEmpty } from 'lodash';
import queryString from 'querystring';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { RouteComponentProps } from 'react-router';
import {
Expand All @@ -44,13 +44,16 @@ import {
} from '../../../../redux/reducers/opensearch';
import { APP_PATH, PLUGIN_NAME } from '../../../../utils/constants';
import { DETECTOR_STATE } from '../../../../../server/utils/constants';
import { getVisibleOptions, sanitizeSearchText } from '../../../utils/helpers';
import {
getAllDetectorsQueryParamsWithDataSourceId,
getVisibleOptions,
sanitizeSearchText,
} from '../../../utils/helpers';
import { EmptyDetectorMessage } from '../../components/EmptyMessage/EmptyMessage';
import { ListFilters } from '../../components/ListFilters/ListFilters';
import {
MAX_DETECTORS,
MAX_SELECTED_INDICES,
GET_ALL_DETECTORS_QUERY_PARAMS,
ALL_DETECTOR_STATES,
ALL_INDICES,
SINGLE_DETECTOR_NOT_FOUND_MSG,
Expand Down Expand Up @@ -78,8 +81,13 @@ import {
NO_PERMISSIONS_KEY_WORD,
prettifyErrorMessage,
} from '../../../../../server/utils/helpers';
import { CoreStart } from '../../../../../../../src/core/public';
import { CoreStart, MountPoint } from '../../../../../../../src/core/public';
import { CoreServicesContext } from '../../../../components/CoreServices/CoreServices';
import {
DataSourceManagementPluginSetup,
DataSourceSelectableConfig,
} from '../../../../../../../src/plugins/data_source_management/public';
import { getNotifications, getSavedObjectsClient } from '../../../../services';

export interface ListRouterParams {
from: string;
Expand All @@ -88,13 +96,19 @@ export interface ListRouterParams {
indices: string;
sortDirection: SORT_DIRECTION;
sortField: string;
dataSourceId: string;
}
interface ListProps extends RouteComponentProps<ListRouterParams> {
dataSourceEnabled: boolean;
dataSourceManagement: DataSourceManagementPluginSetup;
ohltyler marked this conversation as resolved.
Show resolved Hide resolved
setActionMenu: (menuMount: MountPoint | undefined) => void;
}
interface ListProps extends RouteComponentProps<ListRouterParams> {}
interface ListState {
page: number;
queryParams: GetDetectorsQueryParams;
selectedDetectorStates: DETECTOR_STATE[];
selectedIndices: string[];
selectedDataSourceId: string;
}
interface ConfirmModalState {
isOpen: boolean;
Expand Down Expand Up @@ -198,6 +212,9 @@ export const DetectorList = (props: ListProps) => {
selectedIndices: queryParams.indices
? queryParams.indices.split(',')
: ALL_INDICES,
selectedDataSourceId: queryParams.dataSourceId
? queryParams.dataSourceId
: '',
});

// Set breadcrumbs on page initialization
Expand All @@ -215,6 +232,7 @@ export const DetectorList = (props: ListProps) => {
...state.queryParams,
indices: state.selectedIndices.join(','),
from: state.page * state.queryParams.size,
dataSourceId: state.selectedDataSourceId,
};

history.replace({
Expand All @@ -229,6 +247,7 @@ export const DetectorList = (props: ListProps) => {
state.queryParams,
state.selectedDetectorStates,
state.selectedIndices,
state.selectedDataSourceId,
]);

// Handle all filtering / sorting of detectors
Expand All @@ -246,7 +265,8 @@ export const DetectorList = (props: ListProps) => {
const curDetectorsToDisplay = getDetectorsToDisplay(
curSelectedDetectors,
state.page,
state.queryParams.size
state.queryParams.size,
state.selectedDataSourceId
);
setDetectorsToDisplay(curDetectorsToDisplay);

Expand All @@ -273,7 +293,11 @@ export const DetectorList = (props: ListProps) => {
}, [confirmModalState.isRequestingToClose, isLoading]);

const getUpdatedDetectors = async () => {
dispatch(getDetectorList(GET_ALL_DETECTORS_QUERY_PARAMS));
dispatch(
getDetectorList(
getAllDetectorsQueryParamsWithDataSourceId(state.selectedDataSourceId)
)
);
};

const handlePageChange = (pageNumber: number) => {
Expand Down Expand Up @@ -552,6 +576,16 @@ export const DetectorList = (props: ListProps) => {
});
};

const handleDataSourceChange = (e) => {
const dataConnectionId = e[0] ? e[0].id : undefined;
jackiehanyang marked this conversation as resolved.
Show resolved Hide resolved

setState({
...state,
page: 0,
selectedDataSourceId: dataConnectionId,
});
};

const getConfirmModal = () => {
if (confirmModalState.isOpen) {
//@ts-ignore
Expand Down Expand Up @@ -626,9 +660,28 @@ export const DetectorList = (props: ListProps) => {

const confirmModal = getConfirmModal();

const DataSourceMenu =
props.dataSourceManagement.ui.getDataSourceMenu<DataSourceSelectableConfig>();
const renderDataSourceComponent = useMemo(() => {
return (
<DataSourceMenu
setMenuMountPoint={props.setActionMenu}
componentType={'DataSourceSelectable'}
componentConfig={{
fullWidth: false,
savedObjects: getSavedObjectsClient(),
notifications: getNotifications(),
onSelectedDataSources: (dataSources) =>
handleDataSourceChange(dataSources),
}}
/>
);
}, [getSavedObjectsClient(), getNotifications(), props.setActionMenu]);

return (
<EuiPage>
<EuiPageBody>
{props.dataSourceEnabled && renderDataSourceComponent}
<ContentPanel
title={
isLoading
Expand Down
19 changes: 16 additions & 3 deletions public/pages/main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,26 @@ import { DefineDetector } from '../DefineDetector/containers/DefineDetector';
import { ConfigureModel } from '../ConfigureModel/containers/ConfigureModel';
import { DashboardOverview } from '../Dashboard/Container/DashboardOverview';
import { CoreServicesConsumer } from '../../components/CoreServices/CoreServices';
import { CoreStart } from '../../../../../src/core/public';
import { CoreStart, MountPoint } from '../../../../../src/core/public';
import { AnomalyDetectionOverview } from '../Overview';
import { DataSourceManagementPluginSetup } from '../../../../../src/plugins/data_source_management/public';

enum Navigation {
AnomalyDetection = 'Anomaly detection',
Dashboard = 'Dashboard',
Detectors = 'Detectors',
}

interface MainProps extends RouteComponentProps {}
interface MainProps extends RouteComponentProps {
dataSourceEnabled: boolean;
dataSourceManagement: DataSourceManagementPluginSetup;
setHeaderActionMenu: (menuMount: MountPoint | undefined) => void;
}

export function Main(props: MainProps) {
const { dataSourceEnabled, dataSourceManagement, setHeaderActionMenu } =
props;

const hideSideNavBar = useSelector(
(state: AppState) => state.adApp.hideSideNavBar
);
Expand Down Expand Up @@ -83,7 +91,12 @@ export function Main(props: MainProps) {
exact
path={APP_PATH.LIST_DETECTORS}
render={(props: RouteComponentProps<ListRouterParams>) => (
<DetectorList {...props} />
<DetectorList
dataSourceEnabled={dataSourceEnabled}
dataSourceManagement={dataSourceManagement}
setActionMenu={setHeaderActionMenu}
{...props}
/>
)}
/>
<Route
Expand Down
20 changes: 18 additions & 2 deletions public/pages/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { CatIndex, IndexAlias } from '../../../server/models/types';
import sortBy from 'lodash/sortBy';
import { DetectorListItem } from '../../models/interfaces';
import { SORT_DIRECTION } from '../../../server/utils/constants';
import { ALL_INDICES, ALL_DETECTOR_STATES } from './constants';
import { ALL_INDICES, ALL_DETECTOR_STATES, MAX_DETECTORS } from './constants';
import { DETECTOR_STATE } from '../../../server/utils/constants';
import { timeFormatter } from '@elastic/charts';

Expand Down Expand Up @@ -96,8 +96,12 @@ export const filterAndSortDetectors = (
export const getDetectorsToDisplay = (
detectors: DetectorListItem[],
page: number,
size: number
size: number,
dataSourceId: string
) => {
detectors.forEach((detector) => {
detector.dataSourceId = dataSourceId;
});
jackiehanyang marked this conversation as resolved.
Show resolved Hide resolved
return detectors.slice(size * page, page * size + size);
};

Expand All @@ -112,3 +116,15 @@ export const formatNumber = (data: any) => {
return '';
}
};

export const getAllDetectorsQueryParamsWithDataSourceId = (
dataSourceId: string
) => ({
from: 0,
search: '',
indices: '',
size: MAX_DETECTORS,
sortDirection: SORT_DIRECTION.ASC,
sortField: 'name',
dataSourceId: dataSourceId,
});
11 changes: 10 additions & 1 deletion public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
setUiActions,
setUISettings,
setQueryService,
setSavedObjectsClient,
} from './services';
import { AnomalyDetectionOpenSearchDashboardsPluginStart } from 'public';
import {
Expand All @@ -43,6 +44,7 @@ import {
} from '../../../src/plugins/vis_augmenter/public';
import { UiActionsStart } from '../../../src/plugins/ui_actions/public';
import { DataPublicPluginStart } from '../../../src/plugins/data/public';
import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public';

declare module '../../../src/plugins/ui_actions/public' {
export interface ActionContextMapping {
Expand All @@ -55,6 +57,7 @@ export interface AnomalyDetectionSetupDeps {
embeddable: EmbeddableSetup;
notifications: NotificationsSetup;
visAugmenter: VisAugmenterSetup;
dataSourceManagement: DataSourceManagementPluginSetup;
//uiActions: UiActionsSetup;
}

Expand Down Expand Up @@ -82,7 +85,12 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin
mount: async (params: AppMountParameters) => {
const { renderApp } = await import('./anomaly_detection_app');
const [coreStart] = await core.getStartServices();
return renderApp(coreStart, params);
return renderApp(
coreStart,
params,
plugins.dataSourceManagement,
plugins.dataSource
);
},
});

Expand Down Expand Up @@ -116,6 +124,7 @@ export class AnomalyDetectionOpenSearchDashboardsPlugin
setNotifications(core.notifications);
setUiActions(uiActions);
setQueryService(data.query);
setSavedObjectsClient(core.savedObjects.client);
return {};
}
}
4 changes: 4 additions & 0 deletions public/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export const [getUISettings, setUISettings] =
export const [getQueryService, setQueryService] =
createGetterSetter<DataPublicPluginStart['query']>('Query');

export const [getSavedObjectsClient, setSavedObjectsClient] =
createGetterSetter<CoreStart['savedObjects']['client']>('SavedObjectsClient');

// This is primarily used for mocking this module and each of its fns in tests.
export default {
getSavedFeatureAnywhereLoader,
Expand All @@ -49,4 +52,5 @@ export default {
getOverlays,
setUISettings,
setQueryService,
getSavedObjectsClient,
};
1 change: 1 addition & 0 deletions server/models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export type GetDetectorsQueryParams = {
indices?: string;
sortDirection: SORT_DIRECTION;
sortField: string;
dataSourceId?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it isn't scalable or consistent to add this ID as part of this particular interface that's used just for the getDetectors() server-side call. We'll need it for all server-side fns, including all of the AD ones, alerting ones, and general cluster ones. Can you explore a common pattern that could be added to all routes, for example, maybe appending or prepending the data source ID in the path itself and parsing out similar to how detectorID is done for some of them is a possibility. All plugins will have the same problem of how to propagate the data source ID from public -> server-side, is there a common pattern being done by others?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding the dataSourceId as port of this particular interface just for this list page. Because for list page, it uses a specific interface for its query params. Since dataSourceId also serves as a query param on this page, so I'm just adding it to this interface. For other pages, I'm appending the data source id the path itself. Please check the pr for detailed page - https://github.com/opensearch-project/anomaly-detection-dashboards-plugin/pull/719/files#diff-cc594889ac44cb130233969adf3da57a18f360a2a77c57ee273aad5f39d6d733

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and cool, looks like some are adjusted that way there. Let's make all of them consistent through the node path the first time though. This will make it much cleaner and avoid making changes to this data model which doesn't logically fit.

};

export type GetAdMonitorsQueryParams = {
Expand Down
Loading
Loading