From e55f421ee0f492925e0d211fd20b7f2b2615a677 Mon Sep 17 00:00:00 2001
From: Amardeepsingh Siglani
Date: Wed, 4 Sep 2024 11:05:08 -0700
Subject: [PATCH] Update url with data source id; redirect on reload if ds id
not present; minor fixes (#1125)
* update url with data source id; redirect on reload if ds id not present; minor fixes
Signed-off-by: Amardeepsingh Siglani
* revert unwanted change
Signed-off-by: Amardeepsingh Siglani
---------
Signed-off-by: Amardeepsingh Siglani
---
.../components/MDS/DataSourceMenuWrapper.tsx | 70 ++++++++++++++----
public/pages/Main/Main.tsx | 42 +++++++----
.../AddThreatIntelSource.tsx | 8 +-
.../Overview/ThreatIntelOverview.tsx | 6 +-
public/security_analytics_app.tsx | 73 +++++++++++++++----
types/shared.ts | 1 -
6 files changed, 149 insertions(+), 51 deletions(-)
diff --git a/public/components/MDS/DataSourceMenuWrapper.tsx b/public/components/MDS/DataSourceMenuWrapper.tsx
index 7589c127..9a5c1049 100644
--- a/public/components/MDS/DataSourceMenuWrapper.tsx
+++ b/public/components/MDS/DataSourceMenuWrapper.tsx
@@ -4,7 +4,7 @@
*/
import React, { useContext } from 'react';
-import { Route, Switch } from 'react-router-dom';
+import { Route, RouteComponentProps, Switch, matchPath } from 'react-router-dom';
import {
DataSourceManagementPluginSetup,
DataSourceSelectableConfig,
@@ -15,7 +15,7 @@ import { ROUTES } from '../../utils/constants';
import { DataSourceContext } from '../../services/DataSourceContext';
import { DataSourceAttributes } from 'src/plugins/data_source/common/data_sources';
-export interface DataSourceMenuWrapperProps {
+export interface DataSourceMenuWrapperProps extends RouteComponentProps {
core: CoreStart;
dataSourceManagement?: DataSourceManagementPluginSetup;
dataSourceMenuReadOnly: boolean;
@@ -31,11 +31,12 @@ export const DataSourceMenuWrapper: React.FC = ({
dataSourceLoading,
setHeaderActionMenu,
dataSourceFilterFn,
+ location,
+ history,
}) => {
if (!dataSourceManagement) {
return null;
}
-
const { dataSource, setDataSource } = useContext(DataSourceContext)!;
const DataSourceMenuViewComponent = dataSourceManagement.ui?.getDataSourceMenu<
DataSourceViewConfig
@@ -44,29 +45,66 @@ export const DataSourceMenuWrapper: React.FC = ({
DataSourceSelectableConfig
>();
+ const readonlyDataSourcePaths = [
+ ROUTES.EDIT_DETECTOR_ALERT_TRIGGERS,
+ ROUTES.EDIT_DETECTOR_DETAILS,
+ ROUTES.EDIT_DETECTOR_RULES,
+ ROUTES.EDIT_FIELD_MAPPINGS,
+ ROUTES.RULES_EDIT,
+ ROUTES.CORRELATION_RULE_EDIT,
+ ROUTES.DETECTOR_DETAILS,
+ `${ROUTES.LOG_TYPES}/:logTypeId`,
+ `${ROUTES.ALERTS}/:detectorId`,
+ `${ROUTES.FINDINGS}/:detectorId`,
+ `${ROUTES.THREAT_INTEL_SOURCE_DETAILS}/:sourceId`,
+ ROUTES.THREAT_INTEL_EDIT_SCAN_CONFIG,
+ ];
+
+ const pathToParentMap = {
+ [ROUTES.EDIT_DETECTOR_ALERT_TRIGGERS]: ROUTES.DETECTORS,
+ [ROUTES.EDIT_DETECTOR_DETAILS]: ROUTES.DETECTORS,
+ [ROUTES.EDIT_DETECTOR_RULES]: ROUTES.DETECTORS,
+ [ROUTES.EDIT_FIELD_MAPPINGS]: ROUTES.DETECTORS,
+ [ROUTES.RULES_EDIT]: ROUTES.RULES,
+ [ROUTES.CORRELATION_RULE_EDIT]: ROUTES.CORRELATION_RULES,
+ [ROUTES.DETECTOR_DETAILS]: ROUTES.DETECTORS,
+ [`${ROUTES.LOG_TYPES}/:logTypeId`]: ROUTES.LOG_TYPES,
+ [`${ROUTES.ALERTS}/:detectorId`]: ROUTES.ALERTS,
+ [`${ROUTES.FINDINGS}/:detectorId`]: ROUTES.FINDINGS,
+ [`${ROUTES.THREAT_INTEL_SOURCE_DETAILS}/:sourceId`]: ROUTES.THREAT_INTEL_OVERVIEW,
+ [ROUTES.THREAT_INTEL_EDIT_SCAN_CONFIG]: ROUTES.THREAT_INTEL_OVERVIEW,
+ };
+
+ const matchedPath = matchPath(location.pathname, {
+ path: readonlyDataSourcePaths,
+ });
+
+ if (matchedPath) {
+ // should have the data source id in url, if not then redirect back to the overview or related page for each path
+ const searchParams = new URLSearchParams(location.search);
+ const dataSourceId = searchParams.get('dataSourceId');
+ if (dataSourceId !== null && dataSourceId !== undefined) {
+ setDataSource([{ id: dataSourceId }]);
+ } else {
+ const parentPath = pathToParentMap[matchedPath.path] || ROUTES.OVERVIEW;
+ history.replace(parentPath);
+ }
+ }
+
const activeOption = dataSourceLoading ? undefined : [dataSource];
return (
{
return (
= ({
componentConfig={{
fullWidth: false,
activeOption: [dataSource],
+ notifications: core.notifications,
+ savedObjects: core.savedObjects.client,
dataSourceFilter: dataSourceFilterFn,
}}
componentType="DataSourceView"
diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx
index 040150ac..78fe978f 100644
--- a/public/pages/Main/Main.tsx
+++ b/public/pages/Main/Main.tsx
@@ -61,10 +61,10 @@ import { ThreatIntelOverview } from '../ThreatIntel/containers/Overview/ThreatIn
import { AddThreatIntelSource } from '../ThreatIntel/containers/AddThreatIntelSource/AddThreatIntelSource';
import { ThreatIntelScanConfigForm } from '../ThreatIntel/containers/ScanConfiguration/ThreatIntelScanConfigForm';
import { ThreatIntelSource } from '../ThreatIntel/containers/ThreatIntelSource/ThreatIntelSource';
-import * as pluginManifest from "../../../opensearch_dashboards.json";
-import { DataSourceAttributes } from "../../../../../src/plugins/data_source/common/data_sources";
-import semver from "semver";
-import queryString from "query-string";
+import * as pluginManifest from '../../../opensearch_dashboards.json';
+import { DataSourceAttributes } from '../../../../../src/plugins/data_source/common/data_sources';
+import semver from 'semver';
+import queryString from 'query-string';
enum Navigation {
SecurityAnalytics = 'Security Analytics',
@@ -202,11 +202,19 @@ export default class Main extends Component {
prevState: Readonly,
snapshot?: any
): void {
- if (this.props.location.pathname === prevProps.location.pathname) {
- return;
+ const pathnameChanged = this.props.location.pathname !== prevProps.location.pathname;
+
+ if (pathnameChanged || this.state.selectedDataSource.id !== prevState.selectedDataSource.id) {
+ const searchParams = new URLSearchParams(this.props.location.search);
+ searchParams.set('dataSourceId', this.state.selectedDataSource.id);
+ this.props.history.replace({
+ search: searchParams.toString(),
+ });
}
- this.updateSelectedNavItem();
+ if (pathnameChanged) {
+ this.updateSelectedNavItem();
+ }
}
setDateTimeFilter = (dateTimeFilter: DateTimeFilter) => {
@@ -399,11 +407,13 @@ export default class Main extends Component {
};
dataSourceFilterFn = (dataSource: SavedObject) => {
- const dataSourceVersion = dataSource?.attributes?.dataSourceVersion || "";
+ const dataSourceVersion = dataSource?.attributes?.dataSourceVersion || '';
const installedPlugins = dataSource?.attributes?.installedPlugins || [];
return (
semver.satisfies(dataSourceVersion, pluginManifest.supportedOSDataSourceVersions) &&
- pluginManifest.requiredOSDataSourcePlugins.every((plugin) => installedPlugins.includes(plugin))
+ pluginManifest.requiredOSDataSourcePlugins.every((plugin) =>
+ installedPlugins.includes(plugin)
+ )
);
};
@@ -447,6 +457,7 @@ export default class Main extends Component {
<>
{multiDataSourceEnabled && (
{
{!dataSourceLoading && services && (
{/* Hide side navigation bar when on any HIDDEN_NAV_ROUTES pages. */}
- {!HIDDEN_NAV_ROUTES.some((route) => pathname.match(route)) && (
- !core.chrome.navGroup.getNavGroupEnabled() &&
-
-
-
- )}
+ {!HIDDEN_NAV_ROUTES.some((route) => pathname.match(route)) &&
+ !core.chrome.navGroup.getNavGroupEnabled() && (
+
+
+
+ )}
{callout ? : null}
{showFlyoutData ? (
@@ -784,6 +795,7 @@ export default class Main extends Component {
);
}}
diff --git a/public/pages/ThreatIntel/containers/AddThreatIntelSource/AddThreatIntelSource.tsx b/public/pages/ThreatIntel/containers/AddThreatIntelSource/AddThreatIntelSource.tsx
index 18be1f19..499f705b 100644
--- a/public/pages/ThreatIntel/containers/AddThreatIntelSource/AddThreatIntelSource.tsx
+++ b/public/pages/ThreatIntel/containers/AddThreatIntelSource/AddThreatIntelSource.tsx
@@ -596,19 +596,21 @@ export const AddThreatIntelSource: React.FC = ({
-
+
-
+
- history.push(ROUTES.THREAT_INTEL_OVERVIEW)}>Cancel
+ history.push(ROUTES.THREAT_INTEL_OVERVIEW)}>
+ Cancel
+
= ({
history,
threatIntelService,
+ dataSource,
}) => {
const [threatIntelSources, setThreatIntelSources] = useState([]);
const [scanConfig, setScanConfig] = useState(undefined);
@@ -136,7 +138,7 @@ export const ThreatIntelOverview: React.FC = ({
searchSources();
getScanConfig();
- }, [threatIntelService]);
+ }, [threatIntelService, dataSource.id]);
const nextStepClickHandlerById: Record = {
['add-source']: addThreatIntelSourceActionHandler,
diff --git a/public/security_analytics_app.tsx b/public/security_analytics_app.tsx
index 39d88f3a..b1723e6d 100644
--- a/public/security_analytics_app.tsx
+++ b/public/security_analytics_app.tsx
@@ -20,6 +20,8 @@ import { CHANNEL_TYPES } from './pages/CreateDetector/components/ConfigureAlerts
import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public';
import { getPlugins, setIsNotificationPluginInstalled } from './utils/helpers';
import { OS_NOTIFICATION_PLUGIN } from './utils/constants';
+import { dataSourceInfo } from './services/utils/constants';
+import { History } from 'history';
import { getBrowserServices } from './services/utils/constants';
export function renderApp(
@@ -37,21 +39,62 @@ export function renderApp(
ReactDOM.render(
(
-
-
-
-
-
-
-
- )}
+ render={(props) => {
+ const originalMethods = {
+ push: props.history.push,
+ replace: props.history.replace,
+ };
+ const wrapper = (method: 'push' | 'replace') => (
+ ...args: Parameters
+ ) => {
+ if (typeof args[0] === 'string') {
+ const url = new URL(args[0], window.location.origin);
+ const searchParams = url.searchParams;
+ searchParams.set('dataSourceId', dataSourceInfo.activeDataSource.id);
+ originalMethods[method](
+ {
+ pathname: url.pathname,
+ search: searchParams.toString(),
+ },
+ ...args.slice(1)
+ );
+ } else if (typeof args[0] === 'object') {
+ const searchParams = new URLSearchParams(args[0].search);
+ searchParams.set('dataSourceId', dataSourceInfo.activeDataSource.id);
+ originalMethods[method](
+ {
+ ...args[0],
+ search: searchParams.toString(),
+ },
+ ...args.slice(1)
+ );
+ } else {
+ originalMethods[method](...args);
+ }
+ };
+
+ props.history = {
+ ...props.history,
+ push: wrapper('push'),
+ replace: wrapper('replace'),
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+ }}
/>
,
params.element
diff --git a/types/shared.ts b/types/shared.ts
index 8d57c05c..1e76c377 100644
--- a/types/shared.ts
+++ b/types/shared.ts
@@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React from 'react';
import { CorrelationFinding } from './Correlations';
import { DetectorHit } from './Detector';
import { Finding, FindingDetailsFlyoutProps } from './Finding';