Skip to content

Commit

Permalink
[8.x] [Security Solution][Alert details] - improving session view exp…
Browse files Browse the repository at this point in the history
…erience in expandable flyout (elastic#200270) (elastic#205834)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Security Solution][Alert details] - improving session view
experience in expandable flyout
(elastic#200270)](elastic#200270)

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

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

<!--BACKPORT [{"author":{"name":"Philippe
Oberti","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-01-08T04:48:13Z","message":"[Security
Solution][Alert details] - improving session view experience in
expandable flyout (elastic#200270)\n\n## Summary\r\n\r\nThis
[PR](elastic#192531) started the\r\nmove
of the analyzer and session view components from the table to
the\r\nflyout. Shortly after we added an advanced settings (via
this\r\n[PR](elastic#194012)) to allow
users to\r\nswitch back and forth between the old table view and the
flyout view.\r\n\r\nThis current PR focuses on the session view
component and enhances its\r\nuser experience, when rendered in the
expandable flyout.\r\n\r\nNo changes should be made for the user in the
table as well as the other\r\nusages of the session view component (like
for example the Kubernetes\r\ndashboard).\r\n\r\n#### Old UI (in
table)\r\n\r\n\r\nhttps://github.com/user-attachments/assets/015b32fc-69bb-4526-a42d-accad085ad43\r\n\r\n####.
New UI (in
flyout)\r\n\r\n\r\nhttps://github.com/user-attachments/assets/9a3eacbf-bf2b-43d4-8e74-ea933ee0d498\r\n\r\nAs
can seen in the video above, when the session view component
is\r\nopened in the expandable flyout, we show the tree view and the
detailed\r\npanel separated. This allow for better use of the horizontal
space,\r\nespecially visible on a wide monitor. This is also combined
with the\r\nfact that the flyout is resizable (and can take the whole
screen) and\r\nthe preview panel is also resizable, to provide more
space to the\r\ndetailed panel.\r\n\r\nNote: the session view full
screen functionality is lost, but this is by\r\ndesign. As mentioned
above, the user can resize the flyout's width to\r\ntake the full
screen, and the flyout's vertical space is already near\r\nfull
height.\r\n\r\n## Code decisions\r\n\r\nTo guarantee as much as possible
that the usage of the Session View\r\ncomponent in the table or in the
other places (like the Kubernetes\r\ndashboard) were not impacted by
this PR, only additive changes were\r\nmade. All these changes are also
protected behind `if` conditions, that\r\nshould only be run when the
correct props are being passed in.\r\nSome components (like the content
of each of the tabs of the detailed\r\npanels - Process, Metadata and
Alerts) as well as a hook, are exposed\r\noutisde of the `session_view`
plugin, to be reused in the expandable\r\nflyout directly.\r\n\r\nCode
changes were kept to a bare minimum in the `session_view`
plugin!\r\n\r\n## What to test\r\n\r\n- functionality of the Session
View component should be exactly the same\r\nwhen used in the table as
when used in the flyout:\r\n- clicking on a row in the tree should
update the detailed panel\r\naccordingly\r\n- jumping to a process from
the detailed panel should correctly update\r\nthe tree\r\n - viewing the
details of an alert should work\r\n - the \r\n- the UI will be mostly
the same, with some small tweaks:\r\n- viewing an alert details now
opens a preview panel instead of the\r\nflyout. The user can go back to
the previous panel by clicking on the\r\n`Back` button in the top-left
corner\r\n- the alerts tab does not show the number of alerts as it
previously\r\nwas. We might be able to get this to work later, but after
discussing\r\nwith Product this is an acceptable solution as the feature
is still\r\nbehind an Advanced Settings\r\n- the `Open details` has been
replaced by a `expand` icon button, to be\r\nmore consistent with the
rest of the UI in the flyout\r\n\r\n### Notes:\r\n- there is a small
update in the analyzer graph to the icon used in the\r\nopen detail
button. We're now using the `expand` icon to be consistent\r\nwith the
Session View component (which already has another `eye` icon)\r\n\r\n##
How to test\r\n\r\n- turn on the
`securitySolution:enableVisualizationsInFlyout`
Advanced\r\nSettings\r\n![Screenshot 2024-12-16 at 5
05\r\n05 PM](https://github.com/user-attachments/assets/e5a937fa-7eaf-46b3-be11-d56224daf821)\r\n-
generate alerts with data for session view (`yarn test:generate
-n\r\nhttp://elastic:changeme@localhost:9200
-k\r\nhttp://elastic:changeme@localhost:5601`)\r\n\r\n---------\r\n\r\nCo-authored-by:
Paulo Silva
<[email protected]>","sha":"d4a3c96fd33131cfb53b192b28ed6af5ab2c22e4","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Threat
Hunting:Investigations","backport:version","v8.18.0"],"title":"[Security
Solution][Alert details] - improving session view experience in
expandable
flyout","number":200270,"url":"https://github.com/elastic/kibana/pull/200270","mergeCommit":{"message":"[Security
Solution][Alert details] - improving session view experience in
expandable flyout (elastic#200270)\n\n## Summary\r\n\r\nThis
[PR](elastic#192531) started the\r\nmove
of the analyzer and session view components from the table to
the\r\nflyout. Shortly after we added an advanced settings (via
this\r\n[PR](elastic#194012)) to allow
users to\r\nswitch back and forth between the old table view and the
flyout view.\r\n\r\nThis current PR focuses on the session view
component and enhances its\r\nuser experience, when rendered in the
expandable flyout.\r\n\r\nNo changes should be made for the user in the
table as well as the other\r\nusages of the session view component (like
for example the Kubernetes\r\ndashboard).\r\n\r\n#### Old UI (in
table)\r\n\r\n\r\nhttps://github.com/user-attachments/assets/015b32fc-69bb-4526-a42d-accad085ad43\r\n\r\n####.
New UI (in
flyout)\r\n\r\n\r\nhttps://github.com/user-attachments/assets/9a3eacbf-bf2b-43d4-8e74-ea933ee0d498\r\n\r\nAs
can seen in the video above, when the session view component
is\r\nopened in the expandable flyout, we show the tree view and the
detailed\r\npanel separated. This allow for better use of the horizontal
space,\r\nespecially visible on a wide monitor. This is also combined
with the\r\nfact that the flyout is resizable (and can take the whole
screen) and\r\nthe preview panel is also resizable, to provide more
space to the\r\ndetailed panel.\r\n\r\nNote: the session view full
screen functionality is lost, but this is by\r\ndesign. As mentioned
above, the user can resize the flyout's width to\r\ntake the full
screen, and the flyout's vertical space is already near\r\nfull
height.\r\n\r\n## Code decisions\r\n\r\nTo guarantee as much as possible
that the usage of the Session View\r\ncomponent in the table or in the
other places (like the Kubernetes\r\ndashboard) were not impacted by
this PR, only additive changes were\r\nmade. All these changes are also
protected behind `if` conditions, that\r\nshould only be run when the
correct props are being passed in.\r\nSome components (like the content
of each of the tabs of the detailed\r\npanels - Process, Metadata and
Alerts) as well as a hook, are exposed\r\noutisde of the `session_view`
plugin, to be reused in the expandable\r\nflyout directly.\r\n\r\nCode
changes were kept to a bare minimum in the `session_view`
plugin!\r\n\r\n## What to test\r\n\r\n- functionality of the Session
View component should be exactly the same\r\nwhen used in the table as
when used in the flyout:\r\n- clicking on a row in the tree should
update the detailed panel\r\naccordingly\r\n- jumping to a process from
the detailed panel should correctly update\r\nthe tree\r\n - viewing the
details of an alert should work\r\n - the \r\n- the UI will be mostly
the same, with some small tweaks:\r\n- viewing an alert details now
opens a preview panel instead of the\r\nflyout. The user can go back to
the previous panel by clicking on the\r\n`Back` button in the top-left
corner\r\n- the alerts tab does not show the number of alerts as it
previously\r\nwas. We might be able to get this to work later, but after
discussing\r\nwith Product this is an acceptable solution as the feature
is still\r\nbehind an Advanced Settings\r\n- the `Open details` has been
replaced by a `expand` icon button, to be\r\nmore consistent with the
rest of the UI in the flyout\r\n\r\n### Notes:\r\n- there is a small
update in the analyzer graph to the icon used in the\r\nopen detail
button. We're now using the `expand` icon to be consistent\r\nwith the
Session View component (which already has another `eye` icon)\r\n\r\n##
How to test\r\n\r\n- turn on the
`securitySolution:enableVisualizationsInFlyout`
Advanced\r\nSettings\r\n![Screenshot 2024-12-16 at 5
05\r\n05 PM](https://github.com/user-attachments/assets/e5a937fa-7eaf-46b3-be11-d56224daf821)\r\n-
generate alerts with data for session view (`yarn test:generate
-n\r\nhttp://elastic:changeme@localhost:9200
-k\r\nhttp://elastic:changeme@localhost:5601`)\r\n\r\n---------\r\n\r\nCo-authored-by:
Paulo Silva
<[email protected]>","sha":"d4a3c96fd33131cfb53b192b28ed6af5ab2c22e4"}},"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/200270","number":200270,"mergeCommit":{"message":"[Security
Solution][Alert details] - improving session view experience in
expandable flyout (elastic#200270)\n\n## Summary\r\n\r\nThis
[PR](elastic#192531) started the\r\nmove
of the analyzer and session view components from the table to
the\r\nflyout. Shortly after we added an advanced settings (via
this\r\n[PR](elastic#194012)) to allow
users to\r\nswitch back and forth between the old table view and the
flyout view.\r\n\r\nThis current PR focuses on the session view
component and enhances its\r\nuser experience, when rendered in the
expandable flyout.\r\n\r\nNo changes should be made for the user in the
table as well as the other\r\nusages of the session view component (like
for example the Kubernetes\r\ndashboard).\r\n\r\n#### Old UI (in
table)\r\n\r\n\r\nhttps://github.com/user-attachments/assets/015b32fc-69bb-4526-a42d-accad085ad43\r\n\r\n####.
New UI (in
flyout)\r\n\r\n\r\nhttps://github.com/user-attachments/assets/9a3eacbf-bf2b-43d4-8e74-ea933ee0d498\r\n\r\nAs
can seen in the video above, when the session view component
is\r\nopened in the expandable flyout, we show the tree view and the
detailed\r\npanel separated. This allow for better use of the horizontal
space,\r\nespecially visible on a wide monitor. This is also combined
with the\r\nfact that the flyout is resizable (and can take the whole
screen) and\r\nthe preview panel is also resizable, to provide more
space to the\r\ndetailed panel.\r\n\r\nNote: the session view full
screen functionality is lost, but this is by\r\ndesign. As mentioned
above, the user can resize the flyout's width to\r\ntake the full
screen, and the flyout's vertical space is already near\r\nfull
height.\r\n\r\n## Code decisions\r\n\r\nTo guarantee as much as possible
that the usage of the Session View\r\ncomponent in the table or in the
other places (like the Kubernetes\r\ndashboard) were not impacted by
this PR, only additive changes were\r\nmade. All these changes are also
protected behind `if` conditions, that\r\nshould only be run when the
correct props are being passed in.\r\nSome components (like the content
of each of the tabs of the detailed\r\npanels - Process, Metadata and
Alerts) as well as a hook, are exposed\r\noutisde of the `session_view`
plugin, to be reused in the expandable\r\nflyout directly.\r\n\r\nCode
changes were kept to a bare minimum in the `session_view`
plugin!\r\n\r\n## What to test\r\n\r\n- functionality of the Session
View component should be exactly the same\r\nwhen used in the table as
when used in the flyout:\r\n- clicking on a row in the tree should
update the detailed panel\r\naccordingly\r\n- jumping to a process from
the detailed panel should correctly update\r\nthe tree\r\n - viewing the
details of an alert should work\r\n - the \r\n- the UI will be mostly
the same, with some small tweaks:\r\n- viewing an alert details now
opens a preview panel instead of the\r\nflyout. The user can go back to
the previous panel by clicking on the\r\n`Back` button in the top-left
corner\r\n- the alerts tab does not show the number of alerts as it
previously\r\nwas. We might be able to get this to work later, but after
discussing\r\nwith Product this is an acceptable solution as the feature
is still\r\nbehind an Advanced Settings\r\n- the `Open details` has been
replaced by a `expand` icon button, to be\r\nmore consistent with the
rest of the UI in the flyout\r\n\r\n### Notes:\r\n- there is a small
update in the analyzer graph to the icon used in the\r\nopen detail
button. We're now using the `expand` icon to be consistent\r\nwith the
Session View component (which already has another `eye` icon)\r\n\r\n##
How to test\r\n\r\n- turn on the
`securitySolution:enableVisualizationsInFlyout`
Advanced\r\nSettings\r\n![Screenshot 2024-12-16 at 5
05\r\n05 PM](https://github.com/user-attachments/assets/e5a937fa-7eaf-46b3-be11-d56224daf821)\r\n-
generate alerts with data for session view (`yarn test:generate
-n\r\nhttp://elastic:changeme@localhost:9200
-k\r\nhttp://elastic:changeme@localhost:5601`)\r\n\r\n---------\r\n\r\nCo-authored-by:
Paulo Silva
<[email protected]>","sha":"d4a3c96fd33131cfb53b192b28ed6af5ab2c22e4"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Philippe Oberti <[email protected]>
  • Loading branch information
kibanamachine and PhilippeOberti authored Jan 8, 2025
1 parent 42ab0ef commit a6b07b9
Show file tree
Hide file tree
Showing 24 changed files with 1,026 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import {
ENTRY_LEADER_ENTITY_ID,
ENTRY_LEADER_START,
} from '../../shared/constants/field_names';
import { useSessionPreview } from '../../right/hooks/use_session_preview';
import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config';
import { useSourcererDataView } from '../../../../sourcerer/containers';
import { mockContextValue } from '../../shared/mocks/mock_context';
import { useLicense } from '../../../../common/hooks/use_license';

jest.mock('../../right/hooks/use_session_preview');
jest.mock('../../shared/hooks/use_session_view_config');
jest.mock('../../../../common/hooks/use_license');
jest.mock('../../../../sourcerer/containers');

Expand Down Expand Up @@ -80,7 +80,7 @@ const renderSessionView = (contextValue: DocumentDetailsContext = mockContextVal

describe('<SessionView />', () => {
beforeEach(() => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
jest.mocked(useSourcererDataView).mockReturnValue({
browserFields: {},
Expand Down Expand Up @@ -121,7 +121,7 @@ describe('<SessionView />', () => {

it('should render error message and text in header if no sessionConfig', () => {
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
(useSessionPreview as jest.Mock).mockReturnValue(null);
(useSessionViewConfig as jest.Mock).mockReturnValue(null);

const { getByTestId } = renderSessionView();
expect(getByTestId(SESSION_VIEW_NO_DATA_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,24 @@
*/

import type { FC } from 'react';
import React, { useCallback, useMemo } from 'react';
import React, { memo, useCallback, useMemo } from 'react';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import type { TableId } from '@kbn/securitysolution-data-table';
import { EuiPanel } from '@elastic/eui';
import {
ANCESTOR_INDEX,
ENTRY_LEADER_ENTITY_ID,
ENTRY_LEADER_START,
} from '../../shared/constants/field_names';
import { getField } from '../../shared/utils';
import type { Process } from '@kbn/session-view-plugin/common';
import type { CustomProcess } from '../../session_view/context';
import { useUserPrivileges } from '../../../../common/components/user_privileges';
import { SESSION_VIEW_TEST_ID } from './test_ids';
import { isActiveTimeline } from '../../../../helpers';
import { useSourcererDataView } from '../../../../sourcerer/containers';
import { DocumentDetailsPreviewPanelKey } from '../../shared/constants/panel_keys';
import {
DocumentDetailsPreviewPanelKey,
DocumentDetailsSessionViewPanelKey,
} from '../../shared/constants/panel_keys';
import { useKibana } from '../../../../common/lib/kibana';
import { useDocumentDetailsContext } from '../../shared/context';
import { SourcererScopeName } from '../../../../sourcerer/store/model';
import { detectionsTimelineIds } from '../../../../timelines/containers/helpers';
import { ALERT_PREVIEW_BANNER } from '../../preview/constants';
import { useLicense } from '../../../../common/hooks/use_license';
import { useSessionPreview } from '../../right/hooks/use_session_preview';
import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config';
import { SessionViewNoDataMessage } from '../../shared/components/session_view_no_data_message';
import { DocumentEventTypes } from '../../../../common/lib/telemetry';

Expand All @@ -35,46 +32,47 @@ export const SESSION_VIEW_ID = 'session-view';
/**
* Session view displayed in the document details expandable flyout left section under the Visualize tab
*/
export const SessionView: FC = () => {
export const SessionView: FC = memo(() => {
const { sessionView, telemetry } = useKibana().services;
const { getFieldsData, indexName, scopeId, dataFormattedForFieldBrowser } =
useDocumentDetailsContext();
const {
eventId,
indexName,
getFieldsData,
scopeId,
dataFormattedForFieldBrowser,
jumpToEntityId,
jumpToCursor,
} = useDocumentDetailsContext();

const { canReadPolicyManagement } = useUserPrivileges().endpointPrivileges;

const sessionViewConfig = useSessionPreview({ getFieldsData, dataFormattedForFieldBrowser });
const sessionViewConfig = useSessionViewConfig({ getFieldsData, dataFormattedForFieldBrowser });
const isEnterprisePlus = useLicense().isEnterprise();
const isEnabled = sessionViewConfig && isEnterprisePlus;

const ancestorIndex = getField(getFieldsData(ANCESTOR_INDEX)); // e.g in case of alert, we want to grab it's origin index
const sessionEntityId = getField(getFieldsData(ENTRY_LEADER_ENTITY_ID)) || '';
const sessionStartTime = getField(getFieldsData(ENTRY_LEADER_START)) || '';
const index = ancestorIndex || indexName;

const sourcererScope = useMemo(() => {
if (isActiveTimeline(scopeId)) {
return SourcererScopeName.timeline;
} else if (detectionsTimelineIds.includes(scopeId as TableId)) {
return SourcererScopeName.detections;
} else {
return SourcererScopeName.default;
}
}, [scopeId]);

const { selectedPatterns } = useSourcererDataView(sourcererScope);
const { selectedPatterns } = useSourcererDataView(SourcererScopeName.detections);
const eventDetailsIndex = useMemo(() => selectedPatterns.join(','), [selectedPatterns]);

const { openPreviewPanel } = useExpandableFlyoutApi();
const { openPreviewPanel, closePreviewPanel } = useExpandableFlyoutApi();
const openAlertDetailsPreview = useCallback(
(eventId?: string, onClose?: () => void) => {
openPreviewPanel({
id: DocumentDetailsPreviewPanelKey,
params: {
id: eventId,
indexName: eventDetailsIndex,
scopeId,
banner: ALERT_PREVIEW_BANNER,
isPreviewMode: true,
},
});
(evtId?: string, onClose?: () => void) => {
// In the SessionView component, when the user clicks on the
// expand button to open a alert in the preview panel, this actually also selects the row and opens
// the detailed panel in preview.
// In order to NOT modify the SessionView code, the setTimeout here guarantees that the alert details preview
// will be opened in second, so that we have a correct order in the opened preview panels
setTimeout(() => {
openPreviewPanel({
id: DocumentDetailsPreviewPanelKey,
params: {
id: evtId,
indexName: eventDetailsIndex,
scopeId,
banner: ALERT_PREVIEW_BANNER,
isPreviewMode: true,
},
});
}, 100);
telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, {
location: scopeId,
panel: 'preview',
Expand All @@ -83,14 +81,63 @@ export const SessionView: FC = () => {
[openPreviewPanel, eventDetailsIndex, scopeId, telemetry]
);

const openDetailsInPreview = useCallback(
(selectedProcess: Process | null) => {
// We cannot pass the original Process object sent from the SessionView component
// as it contains functions (that should not put into Redux)
// and also some recursive properties (that will break rison.encode when updating the URL)
const simplifiedSelectedProcess: CustomProcess | null = selectedProcess
? {
id: selectedProcess.id,
details: selectedProcess.getDetails(),
endTime: selectedProcess.getEndTime(),
}
: null;

openPreviewPanel({
id: DocumentDetailsSessionViewPanelKey,
params: {
eventId,
indexName,
selectedProcess: simplifiedSelectedProcess,
index: sessionViewConfig?.index,
sessionEntityId: sessionViewConfig?.sessionEntityId,
sessionStartTime: sessionViewConfig?.sessionStartTime,
investigatedAlertId: sessionViewConfig?.investigatedAlertId,
scopeId,
jumpToEntityId,
jumpToCursor,
},
});
},
[
openPreviewPanel,
eventId,
indexName,
sessionViewConfig?.index,
sessionViewConfig?.sessionEntityId,
sessionViewConfig?.sessionStartTime,
sessionViewConfig?.investigatedAlertId,
scopeId,
jumpToEntityId,
jumpToCursor,
]
);

const closeDetailsInPreview = useCallback(() => closePreviewPanel(), [closePreviewPanel]);

return isEnabled ? (
<div data-test-subj={SESSION_VIEW_TEST_ID}>
{sessionView.getSessionView({
index,
sessionEntityId,
sessionStartTime,
...sessionViewConfig,
isFullScreen: true,
loadAlertDetails: openAlertDetailsPreview,
openDetailsInExpandableFlyout: (selectedProcess: Process | null) =>
openDetailsInPreview(selectedProcess),
closeDetailsInExpandableFlyout: () => closeDetailsInPreview(),
canReadPolicyManagement,
resetJumpToEntityId: jumpToEntityId,
resetJumpToCursor: jumpToCursor,
})}
</div>
) : (
Expand All @@ -101,6 +148,6 @@ export const SessionView: FC = () => {
/>
</EuiPanel>
);
};
});

SessionView.displayName = 'SessionView';
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TestProviders } from '../../../../common/mock';
import React from 'react';
import { DocumentDetailsContext } from '../../shared/context';
import { SessionPreviewContainer } from './session_preview_container';
import { useSessionPreview } from '../hooks/use_session_preview';
import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config';
import { useLicense } from '../../../../common/hooks/use_license';
import { SESSION_PREVIEW_TEST_ID } from './test_ids';
import {
Expand All @@ -24,7 +24,7 @@ import { mockContextValue } from '../../shared/mocks/mock_context';
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline';

jest.mock('../hooks/use_session_preview');
jest.mock('../../shared/hooks/use_session_view_config');
jest.mock('../../../../common/hooks/use_license');
jest.mock('../../../../common/hooks/use_experimental_features');
jest.mock(
Expand Down Expand Up @@ -84,7 +84,7 @@ describe('SessionPreviewContainer', () => {
});

it('should render component and link in header', () => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId } = renderSessionPreview();
Expand Down Expand Up @@ -115,7 +115,7 @@ describe('SessionPreviewContainer', () => {
});

it('should render error message and text in header if no sessionConfig', () => {
(useSessionPreview as jest.Mock).mockReturnValue(null);
(useSessionViewConfig as jest.Mock).mockReturnValue(null);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId, queryByTestId } = renderSessionPreview();
Expand All @@ -133,7 +133,7 @@ describe('SessionPreviewContainer', () => {
});

it('should render upsell message in header if no correct license', () => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => false });

const { getByTestId, queryByTestId } = renderSessionPreview();
Expand All @@ -152,7 +152,7 @@ describe('SessionPreviewContainer', () => {
});

it('should not render link to session viewer if flyout is open in preview', () => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId, queryByTestId } = renderSessionPreview({
Expand All @@ -179,7 +179,7 @@ describe('SessionPreviewContainer', () => {
});

it('should not render link to session viewer if flyout is open in preview mode', () => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId, queryByTestId } = renderSessionPreview({
Expand All @@ -199,7 +199,7 @@ describe('SessionPreviewContainer', () => {
describe('when visualization in flyout flag is enabled', () => {
it('should open left panel vizualization tab when visualization in flyout flag is on', () => {
mockUseUiSetting.mockReturnValue([true]);
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId } = renderSessionPreview();
Expand All @@ -212,7 +212,7 @@ describe('SessionPreviewContainer', () => {
});

it('should not render link to session viewer if flyout is open in rule preview', () => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId, queryByTestId } = renderSessionPreview({
Expand All @@ -230,7 +230,7 @@ describe('SessionPreviewContainer', () => {
});

it('should not render link to session viewer if flyout is open in preview mode', () => {
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });

const { getByTestId, queryByTestId } = renderSessionPreview({
Expand All @@ -253,7 +253,7 @@ describe('SessionPreviewContainer', () => {
beforeEach(() => {
jest.clearAllMocks();
mockUseUiSetting.mockReturnValue([true]);
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true);
});
Expand Down Expand Up @@ -304,7 +304,7 @@ describe('SessionPreviewContainer', () => {
beforeEach(() => {
jest.clearAllMocks();
mockUseUiSetting.mockReturnValue([false]);
(useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig);
(useSessionViewConfig as jest.Mock).mockReturnValue(sessionViewConfig);
(useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true });
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(true);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../../common/constants';
import { useLicense } from '../../../../common/hooks/use_license';
import { SessionPreview } from './session_preview';
import { useSessionPreview } from '../hooks/use_session_preview';
import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config';
import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline';
import { useDocumentDetailsContext } from '../../shared/context';
import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions';
Expand Down Expand Up @@ -48,7 +48,7 @@ export const SessionPreviewContainer: FC = () => {
);

// decide whether to show the session view or not
const sessionViewConfig = useSessionPreview({ getFieldsData, dataFormattedForFieldBrowser });
const sessionViewConfig = useSessionViewConfig({ getFieldsData, dataFormattedForFieldBrowser });
const isEnterprisePlus = useLicense().isEnterprise();
const isEnabled = sessionViewConfig && isEnterprisePlus;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 { FC } from 'react';
import React, { useMemo } from 'react';
import type { SessionViewPanelPaths } from '.';
import type { SessionViewPanelTabType } from './tabs';
import { FlyoutBody } from '../../shared/components/flyout_body';

export interface PanelContentProps {
/**
* Id of the tab selected in the parent component to display its content
*/
selectedTabId: SessionViewPanelPaths;
/**
* Tabs display right below the flyout's header
*/
tabs: SessionViewPanelTabType[];
}

/**
* SessionView preview panel content, that renders the process, metadata and alerts tab contents.
*/
export const PanelContent: FC<PanelContentProps> = ({ selectedTabId, tabs }) => {
const selectedTabContent = useMemo(() => {
return tabs.find((tab) => tab.id === selectedTabId)?.content;
}, [selectedTabId, tabs]);

return <FlyoutBody>{selectedTabContent}</FlyoutBody>;
};

PanelContent.displayName = 'PanelContent';
Loading

0 comments on commit a6b07b9

Please sign in to comment.