Skip to content

Commit e003960

Browse files
[Security Solution] fix tools flyout title (elastic#263183)
1 parent 67100aa commit e003960

File tree

7 files changed

+212
-138
lines changed

7 files changed

+212
-138
lines changed

x-pack/solutions/security/plugins/security_solution/public/flyout_v2/document/components/title.tsx

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ export interface TitleProps {
2424
* The document to display
2525
*/
2626
hit: DataTableRecord;
27-
/**
28-
* Optional boolean to render the title in a smaller font size.
29-
* Should be used when the component is displayed in a tools flyout header.
30-
*/
31-
isCompact?: boolean;
3227
/**
3328
* Optional boolean to suppress the rule details link even when a rule ID is present.
3429
* Should be used when the component is displayed in a rule preview context.
@@ -41,7 +36,7 @@ export interface TitleProps {
4136
* For alerts: shows the rule name with a warning icon, linked to the rule details page.
4237
* For events: shows the event title with an analyzeEvent icon.
4338
*/
44-
export const Title: FC<TitleProps> = memo(({ hit, isCompact = false, hideLink = false }) => {
39+
export const Title: FC<TitleProps> = memo(({ hit, hideLink = false }) => {
4540
const { services } = useKibana();
4641

4742
const isAlert = useMemo(
@@ -73,25 +68,12 @@ export const Title: FC<TitleProps> = memo(({ hit, isCompact = false, hideLink =
7368
external={false}
7469
data-test-subj={TITLE_LINK_TEST_ID}
7570
>
76-
<FlyoutTitle
77-
title={title}
78-
iconType={iconType}
79-
isLink
80-
isCompact={isCompact}
81-
data-test-subj={TITLE_TEST_ID}
82-
/>
71+
<FlyoutTitle title={title} iconType={iconType} isLink data-test-subj={TITLE_TEST_ID} />
8372
</EuiLink>
8473
);
8574
}
8675

87-
return (
88-
<FlyoutTitle
89-
title={title}
90-
iconType={iconType}
91-
isCompact={isCompact}
92-
data-test-subj={TITLE_TEST_ID}
93-
/>
94-
);
76+
return <FlyoutTitle title={title} iconType={iconType} data-test-subj={TITLE_TEST_ID} />;
9577
});
9678

9779
Title.displayName = 'Title';

x-pack/solutions/security/plugins/security_solution/public/flyout_v2/shared/components/flyout_title.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ export interface FlyoutTitleProps {
3737
* and the title text is changed to link color
3838
*/
3939
isLink?: boolean;
40-
/**
41-
* Optional boolean to render the title in a smaller font size (`xs` instead of `s`).
42-
* Should be used when the component is displayed in a tools flyout header.
43-
*/
44-
isCompact?: boolean;
4540
/**
4641
* Optional data test subject string
4742
*/
@@ -57,7 +52,6 @@ export const FlyoutTitle: FC<FlyoutTitleProps> = memo(
5752
iconType,
5853
iconColor,
5954
isLink = false,
60-
isCompact = false,
6155
'data-test-subj': dataTestSubj = 'flyoutTitle',
6256
}) => {
6357
const { euiTheme } = useEuiTheme();
@@ -80,13 +74,13 @@ export const FlyoutTitle: FC<FlyoutTitleProps> = memo(
8074

8175
const titleComponent = useMemo(() => {
8276
return (
83-
<EuiTitle size={isCompact ? 'xs' : 's'} data-test-subj={`${dataTestSubj}Text`}>
77+
<EuiTitle size="s" data-test-subj={`${dataTestSubj}Text`}>
8478
<EuiTextColor color={isLink ? euiTheme.colors.textPrimary : undefined}>
8579
<span>{title}</span>
8680
</EuiTextColor>
8781
</EuiTitle>
8882
);
89-
}, [dataTestSubj, isCompact, isLink, title, euiTheme.colors.textPrimary]);
83+
}, [dataTestSubj, isLink, title, euiTheme.colors.textPrimary]);
9084

9185
const linkIcon = useMemo(() => {
9286
return (

x-pack/solutions/security/plugins/security_solution/public/flyout_v2/shared/components/test_ids.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,4 @@ export const NOTES_COUNT_TEST_ID = `${PREFIX}HeaderNotesCount` as const;
3636
export const NOTES_LOADING_TEST_ID = `${PREFIX}HeaderNotesLoading` as const;
3737

3838
export const TOOLS_FLYOUT_HEADER_TEST_ID = `${PREFIX}ToolsFlyoutHeader` as const;
39-
export const TOOLS_FLYOUT_HEADER_EXPAND_BUTTON_TEST_ID =
40-
`${PREFIX}ToolsFlyoutHeaderExpandButton` as const;
39+
export const TOOLS_FLYOUT_HEADER_TITLE_TEST_ID = `${PREFIX}ToolsFlyoutHeaderTitle` as const;

x-pack/solutions/security/plugins/security_solution/public/flyout_v2/shared/components/tools_flyout_header.test.tsx

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,15 @@
66
*/
77

88
import React from 'react';
9-
import { render, fireEvent } from '@testing-library/react';
9+
import { render } from '@testing-library/react';
1010
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
1111
import type { DataTableRecord } from '@kbn/discover-utils';
1212
import { ToolsFlyoutHeader } from './tools_flyout_header';
13-
import { TOOLS_FLYOUT_HEADER_TEST_ID, TOOLS_FLYOUT_HEADER_EXPAND_BUTTON_TEST_ID } from './test_ids';
13+
import { TOOLS_FLYOUT_HEADER_TEST_ID } from './test_ids';
1414

15-
const mockOpenSystemFlyout = jest.fn();
16-
17-
jest.mock('../../../common/lib/kibana', () => ({
18-
useKibana: () => ({
19-
services: {
20-
overlays: {
21-
openSystemFlyout: mockOpenSystemFlyout,
22-
},
23-
},
24-
}),
25-
}));
26-
27-
jest.mock('react-redux', () => ({
28-
...jest.requireActual('react-redux'),
29-
useStore: () => ({}),
30-
}));
31-
32-
jest.mock('react-router-dom', () => ({
33-
...jest.requireActual('react-router-dom'),
34-
useHistory: () => ({ push: jest.fn() }),
35-
}));
36-
37-
jest.mock('../hooks/use_default_flyout_properties', () => ({
38-
useDefaultDocumentFlyoutProperties: () => ({ size: 'm' }),
39-
}));
40-
41-
jest.mock('./flyout_provider', () => ({
42-
flyoutProviders: jest.fn(({ children }: { children: React.ReactNode }) => children),
43-
}));
44-
45-
jest.mock('../../document', () => ({
46-
DocumentFlyout: () => <div data-test-subj="mockDocumentFlyout" />,
47-
}));
48-
49-
jest.mock('../../document/components/title', () => ({
50-
Title: ({ hit }: { hit: DataTableRecord }) => (
51-
<div data-test-subj="mockTitle">{String(hit.id)}</div>
15+
jest.mock('./tools_flyout_title', () => ({
16+
ToolsFlyoutTitle: ({ hit }: { hit: DataTableRecord }) => (
17+
<div data-test-subj="mockToolsFlyoutTitle">{String(hit.id)}</div>
5218
),
5319
}));
5420

@@ -78,10 +44,6 @@ const renderHeader = (props: Partial<Parameters<typeof ToolsFlyoutHeader>[0]> =
7844
};
7945

8046
describe('<ToolsFlyoutHeader />', () => {
81-
beforeEach(() => {
82-
jest.clearAllMocks();
83-
});
84-
8547
it('should render the header container', () => {
8648
const { getByTestId } = renderHeader();
8749
expect(getByTestId(TOOLS_FLYOUT_HEADER_TEST_ID)).toBeInTheDocument();
@@ -92,20 +54,9 @@ describe('<ToolsFlyoutHeader />', () => {
9254
expect(getByText('Session view')).toBeInTheDocument();
9355
});
9456

95-
it('should render the expand button', () => {
96-
const { getByTestId } = renderHeader();
97-
expect(getByTestId(TOOLS_FLYOUT_HEADER_EXPAND_BUTTON_TEST_ID)).toBeInTheDocument();
98-
});
99-
100-
it('should call openSystemFlyout when the expand button is clicked', () => {
101-
const { getByTestId } = renderHeader();
102-
fireEvent.click(getByTestId(TOOLS_FLYOUT_HEADER_EXPAND_BUTTON_TEST_ID));
103-
expect(mockOpenSystemFlyout).toHaveBeenCalledTimes(1);
104-
});
105-
106-
it('should render the document title', () => {
57+
it('should render ToolsFlyoutTitle', () => {
10758
const { getByTestId } = renderHeader();
108-
expect(getByTestId('mockTitle')).toBeInTheDocument();
59+
expect(getByTestId('mockToolsFlyoutTitle')).toBeInTheDocument();
10960
});
11061

11162
it('should render the document severity', () => {

x-pack/solutions/security/plugins/security_solution/public/flyout_v2/shared/components/tools_flyout_header.tsx

Lines changed: 10 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,18 @@
66
*/
77

88
import type { FC, ReactNode } from 'react';
9-
import React, { memo, useCallback } from 'react';
10-
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
11-
import { i18n } from '@kbn/i18n';
9+
import React, { memo } from 'react';
10+
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
1211
import type { DataTableRecord } from '@kbn/discover-utils';
13-
import { useHistory } from 'react-router-dom';
14-
import { useStore } from 'react-redux';
1512
import { Timestamp } from '../../document/components/timestamp';
16-
import { Title } from '../../document/components/title';
1713
import { DocumentSeverity } from '../../document/components/severity';
18-
import { useKibana } from '../../../common/lib/kibana';
1914
import type { CellActionRenderer } from './cell_actions';
2015
import { noopCellActionRenderer } from './cell_actions';
21-
import { flyoutProviders } from './flyout_provider';
22-
import { DocumentFlyout } from '../../document';
23-
import { useDefaultDocumentFlyoutProperties } from '../hooks/use_default_flyout_properties';
24-
import { TOOLS_FLYOUT_HEADER_EXPAND_BUTTON_TEST_ID, TOOLS_FLYOUT_HEADER_TEST_ID } from './test_ids';
16+
import { ToolsFlyoutTitle } from './tools_flyout_title';
17+
import { TOOLS_FLYOUT_HEADER_TEST_ID } from './test_ids';
2518

2619
const noop = () => {};
2720

28-
const EXPAND_BUTTON_ARIA_LABEL = i18n.translate(
29-
'xpack.securitySolution.flyout.toolsFlyoutHeader.expandButtonAriaLabel',
30-
{ defaultMessage: 'Open document details' }
31-
);
32-
3321
export interface ToolsFlyoutHeaderProps {
3422
/**
3523
* The document to display
@@ -55,29 +43,6 @@ export interface ToolsFlyoutHeaderProps {
5543
*/
5644
export const ToolsFlyoutHeader: FC<ToolsFlyoutHeaderProps> = memo(
5745
({ hit, title, renderCellActions = noopCellActionRenderer, onAlertUpdated = noop }) => {
58-
const { services } = useKibana();
59-
const store = useStore();
60-
const history = useHistory();
61-
const defaultFlyoutProperties = useDefaultDocumentFlyoutProperties();
62-
63-
const onShowDocument = useCallback(() => {
64-
services.overlays?.openSystemFlyout(
65-
flyoutProviders({
66-
services,
67-
store,
68-
history,
69-
children: (
70-
<DocumentFlyout
71-
hit={hit}
72-
renderCellActions={renderCellActions}
73-
onAlertUpdated={onAlertUpdated}
74-
/>
75-
),
76-
}),
77-
{ ...defaultFlyoutProperties, session: 'inherit' }
78-
);
79-
}, [defaultFlyoutProperties, history, hit, onAlertUpdated, renderCellActions, services, store]);
80-
8146
return (
8247
<EuiFlexGroup
8348
justifyContent="spaceBetween"
@@ -92,22 +57,16 @@ export const ToolsFlyoutHeader: FC<ToolsFlyoutHeaderProps> = memo(
9257
</EuiTitle>
9358
</EuiFlexItem>
9459
<EuiFlexItem grow={false}>
95-
<EuiFlexGroup alignItems="flexEnd" direction="column" gutterSize="xs">
60+
<EuiFlexGroup alignItems="flexEnd" direction="column" gutterSize="none">
9661
<EuiFlexItem>
97-
<EuiFlexGroup alignItems="center" gutterSize="m" responsive={false} wrap={false}>
62+
<EuiFlexGroup alignItems="center" gutterSize="xs" responsive={false} wrap={false}>
9863
<EuiFlexItem grow={false}>
99-
<EuiButtonIcon
100-
iconType="expand"
101-
onClick={onShowDocument}
102-
aria-label={EXPAND_BUTTON_ARIA_LABEL}
103-
size="xs"
104-
color="primary"
105-
data-test-subj={TOOLS_FLYOUT_HEADER_EXPAND_BUTTON_TEST_ID}
64+
<ToolsFlyoutTitle
65+
hit={hit}
66+
renderCellActions={renderCellActions}
67+
onAlertUpdated={onAlertUpdated}
10668
/>
10769
</EuiFlexItem>
108-
<EuiFlexItem grow={false}>
109-
<Title hit={hit} isCompact={true} />
110-
</EuiFlexItem>
11170
<EuiFlexItem grow={false}>
11271
<DocumentSeverity hit={hit} />
11372
</EuiFlexItem>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import React from 'react';
9+
import { render, fireEvent } from '@testing-library/react';
10+
import type { DataTableRecord } from '@kbn/discover-utils';
11+
import { ToolsFlyoutTitle } from './tools_flyout_title';
12+
import { TOOLS_FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids';
13+
14+
const mockOpenSystemFlyout = jest.fn();
15+
16+
jest.mock('../../../common/lib/kibana', () => ({
17+
useKibana: () => ({
18+
services: {
19+
overlays: {
20+
openSystemFlyout: mockOpenSystemFlyout,
21+
},
22+
},
23+
}),
24+
}));
25+
26+
jest.mock('react-redux', () => ({
27+
...jest.requireActual('react-redux'),
28+
useStore: () => ({}),
29+
}));
30+
31+
jest.mock('react-router-dom', () => ({
32+
...jest.requireActual('react-router-dom'),
33+
useHistory: () => ({ push: jest.fn() }),
34+
}));
35+
36+
jest.mock('../hooks/use_default_flyout_properties', () => ({
37+
useDefaultDocumentFlyoutProperties: () => ({ size: 'm' }),
38+
}));
39+
40+
jest.mock('./flyout_provider', () => ({
41+
flyoutProviders: jest.fn(({ children }: { children: React.ReactNode }) => children),
42+
}));
43+
44+
jest.mock('../../document', () => ({
45+
DocumentFlyout: () => <div data-test-subj="mockDocumentFlyout" />,
46+
}));
47+
48+
const createMockHit = (flattened: DataTableRecord['flattened']): DataTableRecord =>
49+
({
50+
id: '1',
51+
raw: {},
52+
flattened,
53+
isAnchor: false,
54+
} as DataTableRecord);
55+
56+
const alertHit = createMockHit({
57+
'event.kind': 'signal',
58+
'kibana.alert.rule.name': 'Test Rule Name',
59+
});
60+
61+
const eventHit = createMockHit({
62+
'event.kind': 'event',
63+
'event.category': 'process',
64+
'process.name': 'test-process',
65+
});
66+
67+
const renderToolsFlyoutTitle = (hit: DataTableRecord) => render(<ToolsFlyoutTitle hit={hit} />);
68+
69+
describe('<ToolsFlyoutTitle />', () => {
70+
beforeEach(() => {
71+
jest.clearAllMocks();
72+
});
73+
74+
it('should render the alert title', () => {
75+
const { getByTestId } = renderToolsFlyoutTitle(alertHit);
76+
expect(getByTestId(TOOLS_FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('Test Rule Name');
77+
});
78+
79+
it('should render the event title', () => {
80+
const { getByTestId } = renderToolsFlyoutTitle(eventHit);
81+
expect(getByTestId(TOOLS_FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('test-process');
82+
});
83+
84+
it('should open the document flyout when clicked', () => {
85+
const { getByTestId } = renderToolsFlyoutTitle(alertHit);
86+
fireEvent.click(getByTestId(TOOLS_FLYOUT_HEADER_TITLE_TEST_ID));
87+
expect(mockOpenSystemFlyout).toHaveBeenCalledTimes(1);
88+
});
89+
});

0 commit comments

Comments
 (0)