diff --git a/src/platform/packages/shared/deeplinks/security/deep_links.ts b/src/platform/packages/shared/deeplinks/security/deep_links.ts index 464003abd369c..cb47043cc4a18 100644 --- a/src/platform/packages/shared/deeplinks/security/deep_links.ts +++ b/src/platform/packages/shared/deeplinks/security/deep_links.ts @@ -11,6 +11,7 @@ export enum SecurityPageName { administration = 'administration', alerts = 'alerts', assets = 'assets', + assetInventory = 'asset_inventory', attackDiscovery = 'attack_discovery', blocklist = 'blocklist', /* diff --git a/x-pack/solutions/security/plugins/asset_inventory/public/application.tsx b/x-pack/solutions/security/plugins/asset_inventory/public/application.tsx deleted file mode 100644 index f442f01d17f7c..0000000000000 --- a/x-pack/solutions/security/plugins/asset_inventory/public/application.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 ReactDOM from 'react-dom'; -import type { AppMountParameters, CoreStart } from '@kbn/core/public'; -import type { AppPluginStartDependencies } from './types'; -import { AssetInventoryApp } from './components/app'; - -export const renderApp = ( - { notifications, http }: CoreStart, - {}: AppPluginStartDependencies, - { appBasePath, element }: AppMountParameters -) => { - ReactDOM.render( - , - element - ); - - return () => ReactDOM.unmountComponentAtNode(element); -}; diff --git a/x-pack/solutions/security/plugins/asset_inventory/public/components/app.tsx b/x-pack/solutions/security/plugins/asset_inventory/public/components/app.tsx index 924091034353b..50040ab9d22d3 100644 --- a/x-pack/solutions/security/plugins/asset_inventory/public/components/app.tsx +++ b/x-pack/solutions/security/plugins/asset_inventory/public/components/app.tsx @@ -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 ( - - - <> - - - -

- -

-
-
- -
- -
-
+ + <> + + + +

+ +

+
+
+ +
+ +
); }; + +// we need to use default exports to import it via React.lazy +export default AssetInventoryApp; // eslint-disable-line import/no-default-export diff --git a/x-pack/solutions/security/plugins/asset_inventory/public/methods/index.tsx b/x-pack/solutions/security/plugins/asset_inventory/public/methods/index.tsx new file mode 100644 index 0000000000000..bc44445b9b14a --- /dev/null +++ b/x-pack/solutions/security/plugins/asset_inventory/public/methods/index.tsx @@ -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 ( + + }> + + + + ); +}; diff --git a/x-pack/solutions/security/plugins/asset_inventory/public/plugin.ts b/x-pack/solutions/security/plugins/asset_inventory/public/plugin.ts index fd2841f5b2335..f6663399e7a2b 100644 --- a/x-pack/solutions/security/plugins/asset_inventory/public/plugin.ts +++ b/x-pack/solutions/security/plugins/asset_inventory/public/plugin.ts @@ -4,12 +4,13 @@ * 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 @@ -17,16 +18,10 @@ export class AssetInventoryPlugin 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); }, }; } diff --git a/x-pack/solutions/security/plugins/asset_inventory/public/types.ts b/x-pack/solutions/security/plugins/asset_inventory/public/types.ts index a551b4d231c3d..2d1f51329e5c9 100644 --- a/x-pack/solutions/security/plugins/asset_inventory/public/types.ts +++ b/x-pack/solutions/security/plugins/asset_inventory/public/types.ts @@ -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 {} diff --git a/x-pack/solutions/security/plugins/asset_inventory/tsconfig.json b/x-pack/solutions/security/plugins/asset_inventory/tsconfig.json index b733fc545be25..b4dd4bdb16a02 100644 --- a/x-pack/solutions/security/plugins/asset_inventory/tsconfig.json +++ b/x-pack/solutions/security/plugins/asset_inventory/tsconfig.json @@ -14,10 +14,5 @@ "../../../../../typings/**/*" ], "exclude": ["target/**/*"], - "kbn_references": [ - "@kbn/core", - "@kbn/i18n-react", - "@kbn/shared-ux-router", - "@kbn/securitysolution-es-utils" - ] + "kbn_references": ["@kbn/core", "@kbn/i18n-react", "@kbn/securitysolution-es-utils"] } diff --git a/x-pack/solutions/security/plugins/security_solution/common/constants.ts b/x-pack/solutions/security/plugins/security_solution/common/constants.ts index 3818813d94a72..3339c97a61a6a 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/constants.ts @@ -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; @@ -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; diff --git a/x-pack/solutions/security/plugins/security_solution/kibana.jsonc b/x-pack/solutions/security/plugins/security_solution/kibana.jsonc index f672378c88df8..0ffd1922fd2ab 100644 --- a/x-pack/solutions/security/plugins/security_solution/kibana.jsonc +++ b/x-pack/solutions/security/plugins/security_solution/kibana.jsonc @@ -16,6 +16,7 @@ ], "requiredPlugins": [ "actions", + "assetInventory", "alerting", "cases", "cloud", diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/categories.ts b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/categories.ts index 8d815ded5a3c4..5cfabe266eda8 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/categories.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/categories.ts @@ -37,6 +37,10 @@ export const CATEGORIES: Array> = [ SecurityPageName.exploreLanding, ], }, + { + type: LinkCategoryType.separator, + linkIds: [SecurityPageName.assetInventory], + }, { type: LinkCategoryType.separator, linkIds: [SecurityPageName.assets], diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/app/translations.ts index 1769a805f488f..79de4e62f0473 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/translations.ts @@ -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', }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/app_links.ts b/x-pack/solutions/security/plugins/security_solution/public/app_links.ts index dca76b1c37f70..d70b96bbd8250 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app_links.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app_links.ts @@ -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'; @@ -32,6 +33,7 @@ export const appLinks: AppLinkItems = Object.freeze([ timelinesLinks, indicatorsLinks, exploreLinks, + assetInventoryLinks, rulesLinks, onboardingLinks, managementLinks, @@ -52,6 +54,7 @@ export const getFilteredLinks = async ( timelinesLinks, indicatorsLinks, exploreLinks, + assetInventoryLinks, rulesLinks, onboardingLinks, managementFilteredLinks, diff --git a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/index.ts b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/index.ts new file mode 100644 index 0000000000000..78f27a3e42328 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/index.ts @@ -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, + }; + } +} diff --git a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts new file mode 100644 index 0000000000000..2eb5902006744 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/links.ts @@ -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, +}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/pages/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/pages/index.tsx new file mode 100644 index 0000000000000..4f7a0f5947c88 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/pages/index.tsx @@ -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 ( + + {assetInventory.getAssetInventoryPage({})} + + + ); +}); + +AssetInventoryContainer.displayName = 'AssetInventoryContainer'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx new file mode 100644 index 0000000000000..5707d859d844e --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/asset_inventory/routes.tsx @@ -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 = () => ( + + + + + +); + +export const routes: SecuritySubPluginRoutes = [ + { + path: ExperimentalFeaturesService.get().assetInventoryStoreEnabled ? ASSET_INVENTORY_PATH : [], + component: AssetInventoryRoutes, + }, +]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/common/components/navigation/security_side_nav/categories.ts b/x-pack/solutions/security/plugins/security_solution/public/common/components/navigation/security_side_nav/categories.ts index cc695d72a8ffc..49f0601dc11c6 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/common/components/navigation/security_side_nav/categories.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/common/components/navigation/security_side_nav/categories.ts @@ -31,4 +31,8 @@ export const CATEGORIES: SeparatorLinkCategory[] = [ SecurityPageName.exploreLanding, ], }, + { + type: LinkCategoryType.separator, + linkIds: [SecurityPageName.assetInventory], + }, ]; diff --git a/x-pack/solutions/security/plugins/security_solution/public/lazy_sub_plugins.tsx b/x-pack/solutions/security/plugins/security_solution/public/lazy_sub_plugins.tsx index 1be423c988397..a399f25fb8bda 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/lazy_sub_plugins.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/lazy_sub_plugins.tsx @@ -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'; @@ -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, diff --git a/x-pack/solutions/security/plugins/security_solution/public/management/links.ts b/x-pack/solutions/security/plugins/security_solution/public/management/links.ts index 49049218d4dc1..909395df8df4f 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/management/links.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/management/links.ts @@ -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', { diff --git a/x-pack/solutions/security/plugins/security_solution/public/plugin.tsx b/x-pack/solutions/security/plugins/security_solution/public/plugin.tsx index 497b92637dad5..64146d5b587e4 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/plugin.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/plugin.tsx @@ -288,6 +288,7 @@ export class Plugin implements IPlugin; alerts: Awaited>; + assetInventory: Awaited>; attackDiscovery: ReturnType; cloudDefend: ReturnType; cloudSecurityPosture: ReturnType; diff --git a/x-pack/solutions/security/plugins/security_solution/tsconfig.json b/x-pack/solutions/security/plugins/security_solution/tsconfig.json index c6f5b8ac09166..655fe3a489694 100644 --- a/x-pack/solutions/security/plugins/security_solution/tsconfig.json +++ b/x-pack/solutions/security/plugins/security_solution/tsconfig.json @@ -215,6 +215,7 @@ "@kbn/cbor", "@kbn/zod", "@kbn/cloud-security-posture", + "@kbn/asset-inventory-plugin", "@kbn/security-solution-distribution-bar", "@kbn/cloud-security-posture-common", "@kbn/cloud-security-posture-graph",