Skip to content

Commit

Permalink
Add 'inventory' to Security navigation menu
Browse files Browse the repository at this point in the history
  • Loading branch information
albertoblaz committed Dec 18, 2024
1 parent 6490c45 commit 5c28360
Show file tree
Hide file tree
Showing 21 changed files with 190 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum SecurityPageName {
administration = 'administration',
alerts = 'alerts',
assets = 'assets',
assetInventory = 'asset_inventory',
attackDiscovery = 'attack_discovery',
blocklist = 'blocklist',
/*
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,26 @@
*/
import React from 'react';
import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
import { BrowserRouter as Router } from '@kbn/shared-ux-router';
import { EuiPageTemplate, EuiTitle } from '@elastic/eui';
import type { CoreStart } from '@kbn/core/public';

interface AssetInventoryAppDeps {
basename: string;
notifications: CoreStart['notifications'];
http: CoreStart['http'];
}

export const AssetInventoryApp = ({ basename }: AssetInventoryAppDeps) => {
const AssetInventoryApp = () => {
return (
<Router basename={basename}>
<I18nProvider>
<>
<EuiPageTemplate restrictWidth="1000px">
<EuiPageTemplate.Header>
<EuiTitle size="l">
<h1>
<FormattedMessage id="assetInventory.helloWorldText" defaultMessage="Inventory" />
</h1>
</EuiTitle>
</EuiPageTemplate.Header>
<EuiPageTemplate.Section />
</EuiPageTemplate>
</>
</I18nProvider>
</Router>
<I18nProvider>
<>
<EuiPageTemplate restrictWidth="1000px">
<EuiPageTemplate.Header>
<EuiTitle size="l">
<h1>
<FormattedMessage id="assetInventory.allAssets" defaultMessage="All Assets" />
</h1>
</EuiTitle>
</EuiPageTemplate.Header>
<EuiPageTemplate.Section />
</EuiPageTemplate>
</>
</I18nProvider>
);
};

// we need to use default exports to import it via React.lazy
export default AssetInventoryApp; // eslint-disable-line import/no-default-export
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React, { lazy, Suspense } from 'react';
import { EuiLoadingSpinner } from '@elastic/eui';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { AppPluginStartDependencies } from '../types';

// Initializing react-query
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,
},
},
});

const AssetInventoryLazy = lazy(() => import('../components/app'));

export const getAssetInventoryLazy = (props: AppPluginStartDependencies) => {
return (
<QueryClientProvider client={queryClient}>
<Suspense fallback={<EuiLoadingSpinner />}>
<AssetInventoryLazy {...props} />
</Suspense>
</QueryClientProvider>
);
};
15 changes: 5 additions & 10 deletions x-pack/solutions/security/plugins/asset_inventory/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,24 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
import type {
AssetInventoryPluginSetup,
AssetInventoryPluginStart,
AppPluginStartDependencies,
} from './types';
import { getAssetInventoryLazy } from './methods';

export class AssetInventoryPlugin
implements Plugin<AssetInventoryPluginSetup, AssetInventoryPluginStart>
{
public setup(core: CoreSetup): AssetInventoryPluginSetup {
return {};
}
public start(
coreStart: CoreStart,
depsStart: AppPluginStartDependencies
): AssetInventoryPluginStart {
public start(coreStart: CoreStart): AssetInventoryPluginStart {
return {
getAssetInventoryPage: async (params: AppMountParameters) => {
// Load application bundle
const { renderApp } = await import('./application');
// Render the application
return renderApp(coreStart, depsStart as AppPluginStartDependencies, params);
getAssetInventoryPage: (assetInventoryDeps: AppPluginStartDependencies) => {
return getAssetInventoryLazy(assetInventoryDeps);
},
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AssetInventoryPluginSetup {}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AssetInventoryPluginStart {}
export interface AssetInventoryPluginStart {
getAssetInventoryPage: (assetInventoryStartDeps: AppPluginStartDependencies) => JSX.Element;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AppPluginStartDependencies {}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export { SecurityPageName } from '@kbn/security-solution-navigation';
*/
export const APP_ID = 'securitySolution' as const;
export const APP_UI_ID = 'securitySolutionUI' as const;
export const ASSET_INVENTORY_FEATURE_ID = 'securitySolutionAssetInventory' as const;
export const ASSISTANT_FEATURE_ID = 'securitySolutionAssistant' as const;
export const ATTACK_DISCOVERY_FEATURE_ID = 'securitySolutionAttackDiscovery' as const;
export const CASES_FEATURE_ID = 'securitySolutionCasesV2' as const;
Expand Down Expand Up @@ -102,6 +103,7 @@ export const EXCEPTIONS_PATH = '/exceptions' as const;
export const EXCEPTION_LIST_DETAIL_PATH = `${EXCEPTIONS_PATH}/details/:detailName` as const;
export const HOSTS_PATH = '/hosts' as const;
export const ATTACK_DISCOVERY_PATH = '/attack_discovery' as const;
export const ASSET_INVENTORY_PATH = '/asset_inventory' as const;
export const USERS_PATH = '/users' as const;
export const KUBERNETES_PATH = '/kubernetes' as const;
export const NETWORK_PATH = '/network' as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
],
"requiredPlugins": [
"actions",
"assetInventory",
"alerting",
"cases",
"cloud",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export const CATEGORIES: Array<SeparatorLinkCategory<SolutionPageName>> = [
SecurityPageName.exploreLanding,
],
},
{
type: LinkCategoryType.separator,
linkIds: [SecurityPageName.assetInventory],
},
{
type: LinkCategoryType.separator,
linkIds: [SecurityPageName.assets],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ export const ATTACK_DISCOVERY = i18n.translate(
}
);

export const INVENTORY = i18n.translate('xpack.securitySolution.navigation.inventory', {
defaultMessage: 'Inventory',
});

export const TIMELINES = i18n.translate('xpack.securitySolution.navigation.timelines', {
defaultMessage: 'Timelines',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import type { CoreStart } from '@kbn/core/public';

import { links as attackDiscoveryLinks } from './attack_discovery/links';
import { links as assetInventoryLinks } from './asset_inventory/links';
import type { AppLinkItems } from './common/links/types';
import { indicatorsLinks } from './threat_intelligence/links';
import { links as alertsLinks } from './detections/links';
Expand All @@ -32,6 +33,7 @@ export const appLinks: AppLinkItems = Object.freeze([
timelinesLinks,
indicatorsLinks,
exploreLinks,
assetInventoryLinks,
rulesLinks,
onboardingLinks,
managementLinks,
Expand All @@ -52,6 +54,7 @@ export const getFilteredLinks = async (
timelinesLinks,
indicatorsLinks,
exploreLinks,
assetInventoryLinks,
rulesLinks,
onboardingLinks,
managementFilteredLinks,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { SecuritySubPlugin } from '../app/types';
import { routes } from './routes';

export class AssetInventory {
public setup() {}

public start(): SecuritySubPlugin {
return {
routes,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { i18n } from '@kbn/i18n';

import { INVENTORY } from '../app/translations';
import { ASSET_INVENTORY_PATH, SecurityPageName, SERVER_APP_ID } from '../../common/constants';
import type { LinkItem } from '../common/links/types';

export const links: LinkItem = {
capabilities: [`${SERVER_APP_ID}.show`],
globalNavPosition: 10,
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.inventory', {
defaultMessage: 'Inventory',
}),
],
experimentalKey: 'assetInventoryStoreEnabled',
id: SecurityPageName.assetInventory,
path: ASSET_INVENTORY_PATH,
title: INVENTORY,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper';
import { useKibana } from '../../common/lib/kibana';
import { SecurityPageName } from '../../../common/constants';
import { SpyRoute } from '../../common/utils/route/spy_routes';

export const AssetInventoryContainer = React.memo(() => {
const { assetInventory } = useKibana().services;

return (
<SecuritySolutionPageWrapper noPadding>
{assetInventory.getAssetInventoryPage({})}
<SpyRoute pageName={SecurityPageName.assetInventory} />
</SecuritySolutionPageWrapper>
);
});

AssetInventoryContainer.displayName = 'AssetInventoryContainer';
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import type { SecuritySubPluginRoutes } from '../app/types';
import { SecurityPageName } from '../app/types';
import { ASSET_INVENTORY_PATH } from '../../common/constants';
import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper';
import { SecurityRoutePageWrapper } from '../common/components/security_route_page_wrapper';
import { ExperimentalFeaturesService } from '../common/experimental_features_service';
import { AssetInventoryContainer } from './pages';

export const AssetInventoryRoutes = () => (
<PluginTemplateWrapper>
<SecurityRoutePageWrapper pageName={SecurityPageName.assetInventory}>
<AssetInventoryContainer />
</SecurityRoutePageWrapper>
</PluginTemplateWrapper>
);

export const routes: SecuritySubPluginRoutes = [
{
path: ExperimentalFeaturesService.get().assetInventoryStoreEnabled ? ASSET_INVENTORY_PATH : [],
component: AssetInventoryRoutes,
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ export const CATEGORIES: SeparatorLinkCategory[] = [
SecurityPageName.exploreLanding,
],
},
{
type: LinkCategoryType.separator,
linkIds: [SecurityPageName.assetInventory],
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* By loading these later we can reduce the initial bundle size and allow users to delay loading these dependencies until they are needed.
*/

import { AssetInventory } from './asset_inventory';
import { AttackDiscovery } from './attack_discovery';
import { Cases } from './cases';
import { Detections } from './detections';
Expand All @@ -35,6 +36,7 @@ import { SiemMigrations } from './siem_migrations';
* The classes used to instantiate the sub plugins. These are grouped into a single object for the sake of bundling them in a single dynamic import.
*/
const subPluginClasses = {
AssetInventory,
AttackDiscovery,
Detections,
Cases,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const links: LinkItem = {
path: MANAGE_PATH,
skipUrlState: true,
hideTimeline: true,
globalNavPosition: 10,
globalNavPosition: 11,
capabilities: [`${SERVER_APP_ID}.show`],
globalSearchKeywords: [
i18n.translate('xpack.securitySolution.appLinks.manage', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
const { subPluginClasses } = await this.lazySubPlugins();
this._subPlugins = {
alerts: new subPluginClasses.Detections(),
assetInventory: new subPluginClasses.AssetInventory(),
attackDiscovery: new subPluginClasses.AttackDiscovery(),
rules: new subPluginClasses.Rules(),
exceptions: new subPluginClasses.Exceptions(),
Expand Down Expand Up @@ -321,6 +322,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
const alerts = await subPlugins.alerts.start(storage, plugins);
return {
alerts,
assetInventory: subPlugins.assetInventory.start(),
attackDiscovery: subPlugins.attackDiscovery.start(),
cases: subPlugins.cases.start(),
cloudDefend: subPlugins.cloudDefend.start(),
Expand Down
Loading

0 comments on commit 5c28360

Please sign in to comment.