Skip to content

Commit 91aa8e0

Browse files
[Security Solution] Remove draggable wrapper and data provider props (#212589)
## Summary This PR is a follow up clean up of draggables after [this PR](#207959) that removed `isDraggable` prop everywhere. This is part 2 of the draggable clean ups listed in #212593. Included in this PR: 1. Removed the creation of data provider props in `DefaultDraggable`. The security cell actions only require `field` and `value`, so creating the data provider object and later taking just the query fields are redundant. 2. Merged `CellActionWrapper`, `DraggableWrapper` and `DefaultDraggable` into `CellActionsRenderer`, moved files to cell actions folder 4. Updated Zeek and suricata components to call `CellActionsRenderer` directly and removed the tooltips 5. Updated tests Before and after in flow charts **Before** *props in red are used to create data provider and are now obsolete <img width="1345" height="706" alt="image" src="https://github.com/user-attachments/assets/406b84bd-9577-4fb3-9987-27b947eb62fb" /> **After** <img width="1071" height="707" alt="image" src="https://github.com/user-attachments/assets/4233ed14-4d46-432e-a22c-d416499aeb76" /> ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
1 parent 55a4861 commit 91aa8e0

File tree

73 files changed

+1167
-1886
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1167
-1886
lines changed

packages/kbn-babel-preset/styled_components_files.js

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/solutions/security/plugins/security_solution/public/common/components/cell_actions/__snapshots__/cell_actions_renderer.test.tsx.snap

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
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 { render } from '@testing-library/react';
9+
import React from 'react';
10+
import { TableId } from '@kbn/securitysolution-data-table';
11+
import { TestProviders } from '../../mock';
12+
import { TimelineId } from '../../../../common/types';
13+
import { ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID } from '../../../timelines/components/row_renderers_browser/constants';
14+
15+
import { CellActionsRenderer } from './cell_actions_renderer';
16+
17+
jest.mock('../../lib/kibana');
18+
19+
const MockSecurityCellActions = jest.fn(({ children }: { children: React.ReactNode }) => (
20+
<div data-test-subj="mockSecurityCellActions">{children}</div>
21+
));
22+
jest.mock('.', () => ({
23+
...jest.requireActual('.'),
24+
SecurityCellActions: (params: { children: React.ReactNode }) => MockSecurityCellActions(params),
25+
}));
26+
27+
const mockSourcererScopeId = 'testSourcererScopeId';
28+
jest.mock('../../../helpers', () => ({
29+
getSourcererScopeId: jest.fn(() => mockSourcererScopeId),
30+
}));
31+
32+
describe('cell actions renderer', () => {
33+
describe('rendering', () => {
34+
test('it renders theCellActionsRenderer', () => {
35+
const { container } = render(
36+
<CellActionsRenderer field="some-field" value="some-value" queryValue="some-query-value">
37+
<span>{'A child of this'}</span>
38+
</CellActionsRenderer>
39+
);
40+
expect(container.firstChild).toMatchSnapshot();
41+
});
42+
});
43+
44+
describe('CellActionsRenderer', () => {
45+
test('it works with just an id, field, and value and is some value', () => {
46+
const field = 'some-field';
47+
const value = 'some value';
48+
const { getByText } = render(
49+
<TestProviders>
50+
<CellActionsRenderer field={field} value={value} />
51+
</TestProviders>
52+
);
53+
expect(getByText(value)).toBeInTheDocument();
54+
});
55+
56+
test('it returns null if value is undefined', () => {
57+
const { container } = render(<CellActionsRenderer field="some-field" value={undefined} />);
58+
expect(container.firstChild).toBeNull();
59+
});
60+
61+
test('it returns null if value is null', () => {
62+
const { container } = render(<CellActionsRenderer field="some-field" value={null} />);
63+
expect(container.firstChild).toBeNull();
64+
});
65+
66+
test('it renders content with tooltip when tooltip is not explicitly provided', () => {
67+
const { getByText } = render(
68+
<TestProviders>
69+
<CellActionsRenderer field="source.bytes" value="a field value" />
70+
</TestProviders>
71+
);
72+
73+
expect(getByText('a field value')).toBeInTheDocument();
74+
});
75+
76+
test('it renders content with custom tooltip when string is provided', () => {
77+
const { getByText } = render(
78+
<TestProviders>
79+
<CellActionsRenderer
80+
field="source.bytes"
81+
tooltipContent="default string tooltip"
82+
value="a field value"
83+
/>
84+
</TestProviders>
85+
);
86+
87+
expect(getByText('a field value')).toBeInTheDocument();
88+
});
89+
90+
test('it renders content with custom tooltip when element is provided', () => {
91+
const { getByText } = render(
92+
<TestProviders>
93+
<CellActionsRenderer
94+
field="source.bytes"
95+
tooltipContent={<span>{'tooltip'}</span>}
96+
value="a field value"
97+
/>
98+
</TestProviders>
99+
);
100+
101+
expect(getByText('a field value')).toBeInTheDocument();
102+
});
103+
104+
test('it does NOT render a tooltip when tooltipContent is null', () => {
105+
const { queryByTestId } = render(
106+
<TestProviders>
107+
<CellActionsRenderer field="source.bytes" tooltipContent={null} value="a field value" />
108+
</TestProviders>
109+
);
110+
111+
expect(queryByTestId('source.bytes-tooltip')).not.toBeInTheDocument();
112+
});
113+
});
114+
115+
describe('CellActionsRenderer functionality', () => {
116+
const field = 'host.name';
117+
const value = '12345';
118+
const data = { field, value };
119+
120+
const scopeIdsWithHoverActions = [
121+
undefined,
122+
TimelineId.active,
123+
TableId.alternateTest,
124+
TimelineId.casePage,
125+
TableId.alertsOnAlertsPage,
126+
TableId.alertsOnRuleDetailsPage,
127+
TableId.hostsPageEvents,
128+
TableId.hostsPageSessions,
129+
TableId.kubernetesPageSessions,
130+
TableId.networkPageEvents,
131+
TimelineId.test,
132+
TableId.usersPageEvents,
133+
];
134+
135+
const scopeIdsNoHoverActions = [TableId.rulePreview, ROW_RENDERER_BROWSER_EXAMPLE_TIMELINE_ID];
136+
137+
beforeEach(() => {
138+
jest.clearAllMocks();
139+
});
140+
141+
it('should render cell actions with the content', () => {
142+
const result = render(
143+
<CellActionsRenderer field={field} value={value}>
144+
{'test children'}
145+
</CellActionsRenderer>
146+
);
147+
expect(result.queryByTestId('mockSecurityCellActions')).toBeInTheDocument();
148+
expect(result.queryByText('test children')).toBeInTheDocument();
149+
});
150+
151+
it('should call cell actions with the default props', () => {
152+
render(
153+
<CellActionsRenderer field={field} value={value}>
154+
{'test children'}
155+
</CellActionsRenderer>
156+
);
157+
expect(MockSecurityCellActions).toHaveBeenCalledWith(
158+
expect.objectContaining({
159+
data,
160+
mode: 'hover-down',
161+
sourcererScopeId: mockSourcererScopeId,
162+
disabledActionTypes: [],
163+
metadata: { scopeId: TimelineId.active },
164+
})
165+
);
166+
});
167+
168+
describe('when value is empty', () => {
169+
it('should set an empty array value to the SecurityCellActions component', () => {
170+
render(
171+
<CellActionsRenderer field={field} value={''}>
172+
{'test children'}
173+
</CellActionsRenderer>
174+
);
175+
expect(MockSecurityCellActions).toHaveBeenCalledWith(
176+
expect.objectContaining({ data: { ...data, value: [] } })
177+
);
178+
});
179+
});
180+
181+
describe('when queryValue is provided', () => {
182+
it('should set value to queryValue', () => {
183+
render(
184+
<CellActionsRenderer field={field} value={value} queryValue="testQueryValue">
185+
{'test children'}
186+
</CellActionsRenderer>
187+
);
188+
expect(MockSecurityCellActions).toHaveBeenCalledWith(
189+
expect.objectContaining({ data: { ...data, value: 'testQueryValue' } })
190+
);
191+
});
192+
});
193+
194+
describe('when scopeId is defined', () => {
195+
it('should set the scopeId to the SecurityCellActions component metadata', () => {
196+
render(
197+
<CellActionsRenderer field={field} value={value} scopeId="testScopeId">
198+
{'test children'}
199+
</CellActionsRenderer>
200+
);
201+
expect(MockSecurityCellActions).toHaveBeenCalledWith(
202+
expect.objectContaining({ metadata: { scopeId: 'testScopeId' } })
203+
);
204+
});
205+
});
206+
207+
describe('when hideTopN is true', () => {
208+
it('should set the disabledActionTypes to the SecurityCellActions component', () => {
209+
render(
210+
<CellActionsRenderer field={field} value={value} hideTopN>
211+
{'test children'}
212+
</CellActionsRenderer>
213+
);
214+
expect(MockSecurityCellActions).toHaveBeenCalledWith(
215+
expect.objectContaining({ disabledActionTypes: ['security-cellAction-type-showTopN'] })
216+
);
217+
});
218+
});
219+
220+
scopeIdsWithHoverActions.forEach((scopeId) => {
221+
test(`it renders hover actions (by default) when scopeId is '${scopeId}'`, async () => {
222+
const { getByTestId } = render(
223+
<CellActionsRenderer field={field} value={value} scopeId={scopeId}>
224+
{'test children'}
225+
</CellActionsRenderer>
226+
);
227+
expect(getByTestId('mockSecurityCellActions')).toBeInTheDocument();
228+
});
229+
});
230+
231+
scopeIdsNoHoverActions.forEach((scopeId) => {
232+
test(`it does NOT render hover actions when scopeId is '${scopeId}'`, async () => {
233+
const { queryByTestId } = render(
234+
<CellActionsRenderer field={field} value={value} scopeId={scopeId}>
235+
{'test children'}
236+
</CellActionsRenderer>
237+
);
238+
expect(queryByTestId('mockSecurityCellActions')).not.toBeInTheDocument();
239+
});
240+
});
241+
242+
describe('text truncation styling', () => {
243+
test('it applies text truncation styling when truncate IS specified', () => {
244+
const { getByTestId } = render(
245+
<TestProviders>
246+
<CellActionsRenderer field={field} value={value} truncate>
247+
{'test children'}
248+
</CellActionsRenderer>
249+
</TestProviders>
250+
);
251+
252+
expect(getByTestId('render-truncatable-content')).toBeInTheDocument();
253+
});
254+
255+
test('it does NOT apply text truncation styling when truncate is NOT specified', () => {
256+
const { queryByTestId } = render(
257+
<TestProviders>
258+
<CellActionsRenderer field={field} value={value}>
259+
{'test children'}
260+
</CellActionsRenderer>
261+
</TestProviders>
262+
);
263+
264+
expect(queryByTestId('render-truncatable-content')).not.toBeInTheDocument();
265+
});
266+
});
267+
});
268+
});

0 commit comments

Comments
 (0)