Skip to content

Commit

Permalink
[8.x] [Security Solution] Update preview navigation in entity details…
Browse files Browse the repository at this point in the history
… flyout (#204513) (#204961)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution] Update preview navigation in entity details
flyout (#204513)](#204513)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT
[{"author":{"name":"christineweng","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-12-19T14:46:30Z","message":"[Security
Solution] Update preview navigation in entity details flyout
(#204513)\n\n## Summary\r\n\r\nThis PR enables navigation when an user
is viewing a host or user\r\npreview. The main navigation logic has been
extracted to 2 hooks\r\n`useNavigateToHostDetails` and
`useNavigateToUserDetails`\r\n\r\nTo see the new navigation, enable
feature flag\r\n`newExpandableFlyoutNavigationEnabled`\r\n\r\n**How
navigation used to work:**\r\n\r\n- When an entity details flyout is
open, some sections have navigation\r\nlinks to open the details panel
in the left (i.e. risk contribution,\r\nalert insights etc.)\r\n-
However, these navigations were disabled in a preview mode, and
user\r\nis limited to stay in the original flyout
context\r\n\r\n**Preview navigations now available**\r\n- When the
feature flag is on, navigation links is available\r\n- For example, an
user is on a host preview, and click on `alert`, a new\r\nflyout will be
opened (for the new host context) and the alert insights\r\ndetails
section will be
available.","sha":"715c59dfa9bf9ef1d535c2853fcdd85b9c64b76e","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["backport","v9.0.0","Team:Threat
Hunting","release_note:feature","Team:Threat
Hunting:Investigations","Team:Entity
Analytics","v8.18.0"],"title":"[Security Solution] Update preview
navigation in entity details
flyout","number":204513,"url":"https://github.com/elastic/kibana/pull/204513","mergeCommit":{"message":"[Security
Solution] Update preview navigation in entity details flyout
(#204513)\n\n## Summary\r\n\r\nThis PR enables navigation when an user
is viewing a host or user\r\npreview. The main navigation logic has been
extracted to 2 hooks\r\n`useNavigateToHostDetails` and
`useNavigateToUserDetails`\r\n\r\nTo see the new navigation, enable
feature flag\r\n`newExpandableFlyoutNavigationEnabled`\r\n\r\n**How
navigation used to work:**\r\n\r\n- When an entity details flyout is
open, some sections have navigation\r\nlinks to open the details panel
in the left (i.e. risk contribution,\r\nalert insights etc.)\r\n-
However, these navigations were disabled in a preview mode, and
user\r\nis limited to stay in the original flyout
context\r\n\r\n**Preview navigations now available**\r\n- When the
feature flag is on, navigation links is available\r\n- For example, an
user is on a host preview, and click on `alert`, a new\r\nflyout will be
opened (for the new host context) and the alert insights\r\ndetails
section will be
available.","sha":"715c59dfa9bf9ef1d535c2853fcdd85b9c64b76e"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/204513","number":204513,"mergeCommit":{"message":"[Security
Solution] Update preview navigation in entity details flyout
(#204513)\n\n## Summary\r\n\r\nThis PR enables navigation when an user
is viewing a host or user\r\npreview. The main navigation logic has been
extracted to 2 hooks\r\n`useNavigateToHostDetails` and
`useNavigateToUserDetails`\r\n\r\nTo see the new navigation, enable
feature flag\r\n`newExpandableFlyoutNavigationEnabled`\r\n\r\n**How
navigation used to work:**\r\n\r\n- When an entity details flyout is
open, some sections have navigation\r\nlinks to open the details panel
in the left (i.e. risk contribution,\r\nalert insights etc.)\r\n-
However, these navigations were disabled in a preview mode, and
user\r\nis limited to stay in the original flyout
context\r\n\r\n**Preview navigations now available**\r\n- When the
feature flag is on, navigation links is available\r\n- For example, an
user is on a host preview, and click on `alert`, a new\r\nflyout will be
opened (for the new host context) and the alert insights\r\ndetails
section will be
available.","sha":"715c59dfa9bf9ef1d535c2853fcdd85b9c64b76e"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: christineweng <[email protected]>
  • Loading branch information
kibanamachine and christineweng authored Dec 19, 2024
1 parent 17b5861 commit 8a14346
Show file tree
Hide file tree
Showing 25 changed files with 872 additions and 173 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import React from 'react';
import { render } from '@testing-library/react';
import { AlertsPreview } from './alerts_preview';
import { TestProviders } from '../../../common/mock/test_providers';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import type { ParsedAlertsData } from '../../../overview/components/detection_response/alerts_by_status/types';
import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview';
import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview';
import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score';

const mockAlertsData: ParsedAlertsData = {
open: {
Expand All @@ -35,18 +33,14 @@ const mockAlertsData: ParsedAlertsData = {
// Mock hooks
jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview');
jest.mock('@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview');
jest.mock('../../../entity_analytics/api/hooks/use_risk_score');
jest.mock('@kbn/expandable-flyout');

describe('AlertsPreview', () => {
const mockOpenLeftPanel = jest.fn();

beforeEach(() => {
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel });
(useVulnerabilitiesPreview as jest.Mock).mockReturnValue({
data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, UNKNOWN: 0 } },
});
(useRiskScore as jest.Mock).mockReturnValue({ data: [{ host: { risk: 75 } }] });
(useMisconfigurationPreview as jest.Mock).mockReturnValue({
data: { count: { passed: 1, failed: 1 } },
});
Expand All @@ -58,7 +52,11 @@ describe('AlertsPreview', () => {
it('renders', () => {
const { getByTestId } = render(
<TestProviders>
<AlertsPreview alertsData={mockAlertsData} value="host1" field="host.name" />
<AlertsPreview
alertsData={mockAlertsData}
isLinkEnabled={true}
openDetailsPanel={mockOpenLeftPanel}
/>
</TestProviders>
);

Expand All @@ -68,7 +66,11 @@ describe('AlertsPreview', () => {
it('renders correct alerts number', () => {
const { getByTestId } = render(
<TestProviders>
<AlertsPreview alertsData={mockAlertsData} value="host1" field="host.name" />
<AlertsPreview
alertsData={mockAlertsData}
isLinkEnabled={true}
openDetailsPanel={mockOpenLeftPanel}
/>
</TestProviders>
);

Expand All @@ -78,7 +80,11 @@ describe('AlertsPreview', () => {
it('should render the correct number of distribution bar section based on the number of severities', () => {
const { queryAllByTestId } = render(
<TestProviders>
<AlertsPreview alertsData={mockAlertsData} value="host1" field="host.name" />
<AlertsPreview
alertsData={mockAlertsData}
isLinkEnabled={true}
openDetailsPanel={mockOpenLeftPanel}
/>
</TestProviders>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import { capitalize } from 'lodash';
import type { EuiThemeComputed } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle, useEuiTheme } from '@elastic/eui';
Expand All @@ -18,8 +18,11 @@ import type {
} from '../../../overview/components/detection_response/alerts_by_status/types';
import { ExpandablePanel } from '../../../flyout/shared/components/expandable_panel';
import { getSeverityColor } from '../../../detections/components/alerts_kpis/severity_level_panel/helpers';
import { CspInsightLeftPanelSubTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import { useNavigateEntityInsight } from '../../hooks/use_entity_insight';
import type { EntityDetailsPath } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import {
CspInsightLeftPanelSubTab,
EntityDetailsLeftPanelTab,
} from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';

const AlertsCount = ({
alertsTotal,
Expand Down Expand Up @@ -58,14 +61,14 @@ const AlertsCount = ({

export const AlertsPreview = ({
alertsData,
field,
value,
isPreviewMode,
openDetailsPanel,
isLinkEnabled,
}: {
alertsData: ParsedAlertsData;
field: 'host.name' | 'user.name';
value: string;
isPreviewMode?: boolean;
openDetailsPanel: (path: EntityDetailsPath) => void;
isLinkEnabled: boolean;
}) => {
const { euiTheme } = useEuiTheme();

Expand All @@ -90,15 +93,16 @@ export const AlertsPreview = ({

const hasNonClosedAlerts = totalAlertsCount > 0;

const { goToEntityInsightTab } = useNavigateEntityInsight({
field,
value,
queryIdExtension: isPreviewMode ? 'ALERTS_PREVIEW_TRUE' : 'ALERTS_PREVIEW_FALSE',
subTab: CspInsightLeftPanelSubTab.ALERTS,
});
const goToEntityInsightTab = useCallback(() => {
openDetailsPanel({
tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
subTab: CspInsightLeftPanelSubTab.ALERTS,
});
}, [openDetailsPanel]);

const link = useMemo(
() =>
!isPreviewMode
isLinkEnabled
? {
callback: goToEntityInsightTab,
tooltip: (
Expand All @@ -109,7 +113,7 @@ export const AlertsPreview = ({
),
}
: undefined,
[isPreviewMode, goToEntityInsightTab]
[isLinkEnabled, goToEntityInsightTab]
);
return (
<ExpandablePanel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@ import { AlertsPreview } from './alerts/alerts_preview';
import { useGlobalTime } from '../../common/containers/use_global_time';
import { DETECTION_RESPONSE_ALERTS_BY_STATUS_ID } from '../../overview/components/detection_response/alerts_by_status/types';
import { useNonClosedAlerts } from '../hooks/use_non_closed_alerts';
import type { EntityDetailsPath } from '../../flyout/entity_details/shared/components/left_panel/left_panel_header';

export const EntityInsight = <T,>({
value,
field,
isPreviewMode,
isLinkEnabled,
openDetailsPanel,
}: {
value: string;
field: 'host.name' | 'user.name';
isPreviewMode?: boolean;
isLinkEnabled: boolean;
openDetailsPanel: (path: EntityDetailsPath) => void;
}) => {
const { euiTheme } = useEuiTheme();
const insightContent: React.ReactElement[] = [];
Expand Down Expand Up @@ -55,9 +60,9 @@ export const EntityInsight = <T,>({
<>
<AlertsPreview
alertsData={filteredAlertsData}
field={field}
value={value}
isPreviewMode={isPreviewMode}
isLinkEnabled={isLinkEnabled}
openDetailsPanel={openDetailsPanel}
/>
<EuiSpacer size="s" />
</>
Expand All @@ -67,14 +72,26 @@ export const EntityInsight = <T,>({
if (showMisconfigurationsPreview)
insightContent.push(
<>
<MisconfigurationsPreview value={value} field={field} isPreviewMode={isPreviewMode} />
<MisconfigurationsPreview
value={value}
field={field}
isPreviewMode={isPreviewMode}
isLinkEnabled={isLinkEnabled}
openDetailsPanel={openDetailsPanel}
/>
<EuiSpacer size="s" />
</>
);
if (showVulnerabilitiesPreview)
insightContent.push(
<>
<VulnerabilitiesPreview value={value} field={field} isPreviewMode={isPreviewMode} />
<VulnerabilitiesPreview
value={value}
field={field}
isPreviewMode={isPreviewMode}
isLinkEnabled={isLinkEnabled}
openDetailsPanel={openDetailsPanel}
/>
<EuiSpacer size="s" />
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,19 @@ import { render } from '@testing-library/react';
import { MisconfigurationsPreview } from './misconfiguration_preview';
import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview';
import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview';
import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { TestProviders } from '../../../common/mock/test_providers';

// Mock hooks
jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview');
jest.mock('@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview');
jest.mock('../../../entity_analytics/api/hooks/use_risk_score');
jest.mock('@kbn/expandable-flyout');

describe('MisconfigurationsPreview', () => {
const mockOpenLeftPanel = jest.fn();

beforeEach(() => {
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel });
(useVulnerabilitiesPreview as jest.Mock).mockReturnValue({
data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, UNKNOWN: 0 } },
});
(useRiskScore as jest.Mock).mockReturnValue({ data: [{ host: { risk: 75 } }] });
(useMisconfigurationPreview as jest.Mock).mockReturnValue({
data: { count: { passed: 1, failed: 1 } },
});
Expand All @@ -37,7 +31,12 @@ describe('MisconfigurationsPreview', () => {
it('renders', () => {
const { getByTestId } = render(
<TestProviders>
<MisconfigurationsPreview value="host1" field="host.name" />
<MisconfigurationsPreview
value="host1"
field="host.name"
isLinkEnabled={true}
openDetailsPanel={mockOpenLeftPanel}
/>
</TestProviders>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { useEffect, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo } from 'react';
import { css } from '@emotion/react';
import type { EuiThemeComputed } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, useEuiTheme, EuiTitle } from '@elastic/eui';
Expand All @@ -20,8 +20,11 @@ import {
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { ExpandablePanel } from '../../../flyout/shared/components/expandable_panel';
import { CspInsightLeftPanelSubTab } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import { useNavigateEntityInsight } from '../../hooks/use_entity_insight';
import type { EntityDetailsPath } from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';
import {
CspInsightLeftPanelSubTab,
EntityDetailsLeftPanelTab,
} from '../../../flyout/entity_details/shared/components/left_panel/left_panel_header';

export const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: number) => {
if (passedFindingsStats === 0 && failedFindingsStats === 0) return [];
Expand Down Expand Up @@ -88,10 +91,14 @@ export const MisconfigurationsPreview = ({
value,
field,
isPreviewMode,
isLinkEnabled,
openDetailsPanel,
}: {
value: string;
field: 'host.name' | 'user.name';
isPreviewMode?: boolean;
isLinkEnabled: boolean;
openDetailsPanel: (path: EntityDetailsPath) => void;
}) => {
const { hasMisconfigurationFindings, passedFindings, failedFindings } = useHasMisconfigurations(
field,
Expand All @@ -103,15 +110,16 @@ export const MisconfigurationsPreview = ({
}, []);
const { euiTheme } = useEuiTheme();

const { goToEntityInsightTab } = useNavigateEntityInsight({
field,
value,
queryIdExtension: 'MISCONFIGURATION_PREVIEW',
subTab: CspInsightLeftPanelSubTab.MISCONFIGURATIONS,
});
const goToEntityInsightTab = useCallback(() => {
openDetailsPanel({
tab: EntityDetailsLeftPanelTab.CSP_INSIGHTS,
subTab: CspInsightLeftPanelSubTab.MISCONFIGURATIONS,
});
}, [openDetailsPanel]);

const link = useMemo(
() =>
!isPreviewMode
isLinkEnabled
? {
callback: goToEntityInsightTab,
tooltip: (
Expand All @@ -122,7 +130,7 @@ export const MisconfigurationsPreview = ({
),
}
: undefined,
[isPreviewMode, goToEntityInsightTab]
[isLinkEnabled, goToEntityInsightTab]
);
return (
<ExpandablePanel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,19 @@ import { render } from '@testing-library/react';
import { VulnerabilitiesPreview } from './vulnerabilities_preview';
import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview';
import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview';
import { useRiskScore } from '../../../entity_analytics/api/hooks/use_risk_score';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import { TestProviders } from '../../../common/mock/test_providers';

// Mock hooks
jest.mock('@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview');
jest.mock('@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview');
jest.mock('../../../entity_analytics/api/hooks/use_risk_score');
jest.mock('@kbn/expandable-flyout');

describe('VulnerabilitiesPreview', () => {
const mockOpenLeftPanel = jest.fn();

beforeEach(() => {
(useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel });
(useVulnerabilitiesPreview as jest.Mock).mockReturnValue({
data: { count: { CRITICAL: 0, HIGH: 1, MEDIUM: 1, LOW: 0, UNKNOWN: 0 } },
});
(useRiskScore as jest.Mock).mockReturnValue({ data: [{ host: { risk: 75 } }] });
(useMisconfigurationPreview as jest.Mock).mockReturnValue({
data: { count: { passed: 1, failed: 1 } },
});
Expand All @@ -37,7 +31,12 @@ describe('VulnerabilitiesPreview', () => {
it('renders', () => {
const { getByTestId } = render(
<TestProviders>
<VulnerabilitiesPreview value="host1" field="host.name" />
<VulnerabilitiesPreview
value="host1"
field="host.name"
isLinkEnabled={true}
openDetailsPanel={mockOpenLeftPanel}
/>
</TestProviders>
);

Expand Down
Loading

0 comments on commit 8a14346

Please sign in to comment.