Skip to content

Commit e314aaf

Browse files
[Security Solution] fix issue where analyzer is not showing when the newDataViewPickerEnabled feature flag is off (#255182)
## Summary This somewhat recent [PR](#245712) that was aiming at fixing a bug related to dataViews with analyzer actually introduced another bug. The code added in that previous PR was verifying that the dataView was correctly loaded before showing analyzer, but the check was done only for the `newDataViewPickerEnabled` feature flag turned on... This PR fixes that issue and handles both the `newDataViewPickerEnabled` feature flag on and off. ### 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) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels.
1 parent 49c8d3b commit e314aaf

File tree

2 files changed

+165
-59
lines changed

2 files changed

+165
-59
lines changed

x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/analyze_graph.test.tsx

Lines changed: 134 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ import { useIsInvestigateInResolverActionEnabled } from '../../../../detections/
2626
import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features';
2727
import { useSelectedPatterns } from '../../../../data_view_manager/hooks/use_selected_patterns';
2828
import { useDataView } from '../../../../data_view_manager/hooks/use_data_view';
29-
import type { DataView } from '@kbn/data-views-plugin/common';
29+
import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
3030
import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub';
31+
import { useSourcererDataView } from '../../../../sourcerer/containers';
3132

3233
jest.mock('react-router-dom', () => {
3334
const actual = jest.requireActual('react-router-dom');
@@ -41,6 +42,7 @@ jest.mock(
4142
);
4243
jest.mock('../../../../common/hooks/use_experimental_features');
4344
jest.mock('../../../../data_view_manager/hooks/use_selected_patterns');
45+
jest.mock('../../../../sourcerer/containers');
4446

4547
const mockUseWhichFlyout = useWhichFlyout as jest.Mock;
4648
const FLYOUT_KEY = 'securitySolution';
@@ -61,6 +63,7 @@ const NO_ANALYZER_MESSAGE =
6163
const dataView: DataView = createStubDataView({
6264
spec: { title: '.alerts-security.alerts-default' },
6365
});
66+
const dataViewSpec: DataViewSpec = createStubDataView({ spec: {} }).toSpec();
6467

6568
const renderAnalyzer = (
6669
contextValue = {
@@ -94,85 +97,160 @@ describe('<AnalyzeGraph />', () => {
9497
});
9598
});
9699

97-
it('renders analyzer graph correctly', () => {
98-
const wrapper = renderAnalyzer();
100+
describe('newDataViewPickerEnabled true', () => {
101+
beforeEach(() => {
102+
(useSourcererDataView as jest.Mock).mockReturnValue({});
103+
});
99104

100-
expect(wrapper.getByTestId(ANALYZER_GRAPH_TEST_ID)).toBeInTheDocument();
101-
});
105+
it('renders analyzer graph correctly', () => {
106+
const wrapper = renderAnalyzer();
102107

103-
it('should render no data message when analyzer is not enabled', () => {
104-
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(false);
108+
expect(wrapper.getByTestId(ANALYZER_GRAPH_TEST_ID)).toBeInTheDocument();
109+
});
105110

106-
const contextValue = {
107-
eventId: 'eventId',
108-
scopeId: TableId.test,
109-
dataAsNestedObject: {},
110-
} as unknown as DocumentDetailsContext;
111+
it('should render no data message when analyzer is not enabled', () => {
112+
(useIsInvestigateInResolverActionEnabled as jest.Mock).mockReturnValue(false);
111113

112-
const { container } = renderAnalyzer(contextValue);
114+
const contextValue = {
115+
eventId: 'eventId',
116+
scopeId: TableId.test,
117+
dataAsNestedObject: {},
118+
} as unknown as DocumentDetailsContext;
113119

114-
expect(container).toHaveTextContent(NO_ANALYZER_MESSAGE);
115-
});
120+
const { container } = renderAnalyzer(contextValue);
116121

117-
it('should show loading spinner while data view is loading', () => {
118-
(useDataView as jest.Mock).mockReturnValue({
119-
status: 'loading',
122+
expect(container).toHaveTextContent(NO_ANALYZER_MESSAGE);
120123
});
121124

122-
const { getByTestId } = renderAnalyzer();
125+
it('should show loading spinner while data view is loading', () => {
126+
(useDataView as jest.Mock).mockReturnValue({
127+
status: 'loading',
128+
});
123129

124-
expect(getByTestId(DATA_VIEW_LOADING_TEST_ID)).toBeInTheDocument();
125-
});
130+
const { getByTestId } = renderAnalyzer();
126131

127-
it('should show loading spinner while data view is pristine', () => {
128-
(useDataView as jest.Mock).mockReturnValue({
129-
status: 'pristine',
132+
expect(getByTestId(DATA_VIEW_LOADING_TEST_ID)).toBeInTheDocument();
130133
});
131134

132-
const { getByTestId } = renderAnalyzer();
135+
it('should show loading spinner while data view is pristine', () => {
136+
(useDataView as jest.Mock).mockReturnValue({
137+
status: 'pristine',
138+
});
133139

134-
expect(getByTestId(DATA_VIEW_LOADING_TEST_ID)).toBeInTheDocument();
135-
});
140+
const { getByTestId } = renderAnalyzer();
136141

137-
it('should show error message if data view is error', () => {
138-
(useDataView as jest.Mock).mockReturnValue({
139-
status: 'error',
142+
expect(getByTestId(DATA_VIEW_LOADING_TEST_ID)).toBeInTheDocument();
140143
});
141144

142-
const { getByTestId } = renderAnalyzer();
145+
it('should show error message if data view is error', () => {
146+
(useDataView as jest.Mock).mockReturnValue({
147+
status: 'error',
148+
});
143149

144-
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
145-
'Unable to retrieve the data view for analyzer'
146-
);
147-
});
150+
const { getByTestId } = renderAnalyzer();
148151

149-
it('should show error message if data view is ready but no matched indices', () => {
150-
(useDataView as jest.Mock).mockReturnValue({
151-
status: 'ready',
152-
dataView: {
153-
...dataView,
154-
hasMatchedIndices: jest.fn().mockReturnValue(false),
155-
},
152+
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
153+
'Unable to retrieve the data view for analyzer'
154+
);
155+
});
156+
157+
it('should show error message if data view is ready but no matched indices', () => {
158+
(useDataView as jest.Mock).mockReturnValue({
159+
status: 'ready',
160+
dataView: {
161+
...dataView,
162+
hasMatchedIndices: jest.fn().mockReturnValue(false),
163+
},
164+
});
165+
166+
const { getByTestId } = renderAnalyzer();
167+
168+
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
169+
'Unable to retrieve the data view for analyzer'
170+
);
156171
});
157172

158-
const { getByTestId } = renderAnalyzer();
173+
it('should open details panel in preview when clicking on view button', () => {
174+
const wrapper = renderAnalyzer();
159175

160-
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
161-
'Unable to retrieve the data view for analyzer'
162-
);
176+
expect(wrapper.getByTestId('resolver:graph-controls:show-panel-button')).toBeInTheDocument();
177+
wrapper.getByTestId('resolver:graph-controls:show-panel-button').click();
178+
expect(mockFlyoutApi.openPreviewPanel).toBeCalledWith({
179+
id: DocumentDetailsAnalyzerPanelKey,
180+
params: {
181+
resolverComponentInstanceID: `${FLYOUT_KEY}-${TableId.test}`,
182+
banner: ANALYZER_PREVIEW_BANNER,
183+
},
184+
});
185+
});
163186
});
164187

165-
it('should open details panel in preview when clicking on view button', () => {
166-
const wrapper = renderAnalyzer();
188+
describe('newDataViewPickerEnabled false', () => {
189+
beforeEach(() => {
190+
jest.clearAllMocks();
167191

168-
expect(wrapper.getByTestId('resolver:graph-controls:show-panel-button')).toBeInTheDocument();
169-
wrapper.getByTestId('resolver:graph-controls:show-panel-button').click();
170-
expect(mockFlyoutApi.openPreviewPanel).toBeCalledWith({
171-
id: DocumentDetailsAnalyzerPanelKey,
172-
params: {
173-
resolverComponentInstanceID: `${FLYOUT_KEY}-${TableId.test}`,
174-
banner: ANALYZER_PREVIEW_BANNER,
175-
},
192+
(useIsExperimentalFeatureEnabled as jest.Mock).mockReturnValue(false);
193+
});
194+
195+
it('should show loading spinner while sourcerer data view is loading', () => {
196+
(useSourcererDataView as jest.Mock).mockReturnValue({
197+
loading: true,
198+
sourcererDataView: dataViewSpec,
199+
});
200+
201+
const { getByTestId } = renderAnalyzer();
202+
203+
expect(getByTestId(DATA_VIEW_LOADING_TEST_ID)).toBeInTheDocument();
204+
});
205+
206+
it('should render an error if the dataViewSpec is undefined', () => {
207+
(useSourcererDataView as jest.Mock).mockReturnValue({
208+
loading: false,
209+
sourcererDataView: undefined,
210+
});
211+
212+
const { getByTestId } = renderAnalyzer();
213+
214+
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
215+
'Unable to retrieve the data view for analyzer'
216+
);
217+
});
218+
219+
it('should render an error if the dataViewSpec is invalid because id is undefined', () => {
220+
(useSourcererDataView as jest.Mock).mockReturnValue({
221+
loading: false,
222+
sourcererDataView: { ...dataViewSpec, id: undefined, title: 'title' },
223+
});
224+
225+
const { getByTestId } = renderAnalyzer();
226+
227+
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
228+
'Unable to retrieve the data view for analyzer'
229+
);
230+
});
231+
232+
it('should render an error if the dataViewSpec is invalid because title is empty', () => {
233+
(useSourcererDataView as jest.Mock).mockReturnValue({
234+
loading: false,
235+
sourcererDataView: { ...dataViewSpec, id: 'id', title: '' },
236+
});
237+
238+
const { getByTestId } = renderAnalyzer();
239+
240+
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent(
241+
'Unable to retrieve the data view for analyzer'
242+
);
243+
});
244+
245+
it('should render the content', () => {
246+
(useSourcererDataView as jest.Mock).mockReturnValue({
247+
loading: false,
248+
sourcererDataView: { ...dataViewSpec, id: 'id', title: 'title' },
249+
});
250+
251+
const { getByTestId } = renderAnalyzer();
252+
253+
expect(getByTestId(ANALYZER_GRAPH_TEST_ID)).toBeInTheDocument();
176254
});
177255
});
178256
});

x-pack/solutions/security/plugins/security_solution/public/flyout/document_details/left/components/analyze_graph.tsx

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,35 @@ export const AnalyzeGraph: FC = () => {
6767
? experimentalAnalyzerPatterns
6868
: oldAnalyzerPatterns;
6969

70-
const { dataView, status } = useDataView(PageScope.analyzer);
70+
const { dataView: experimentalDataView, status: experimentalDataViewStatus } = useDataView(
71+
PageScope.analyzer
72+
);
73+
const { sourcererDataView: oldSourcererDataViewSpec, loading: oldSourcererDataViewIsLoading } =
74+
useSourcererDataView(PageScope.analyzer);
75+
76+
const isLoading: boolean = useMemo(
77+
() =>
78+
newDataViewPickerEnabled
79+
? experimentalDataViewStatus === 'loading' || experimentalDataViewStatus === 'pristine'
80+
: oldSourcererDataViewIsLoading,
81+
[experimentalDataViewStatus, newDataViewPickerEnabled, oldSourcererDataViewIsLoading]
82+
);
83+
84+
const isDataViewInvalid: boolean = useMemo(
85+
() =>
86+
newDataViewPickerEnabled
87+
? experimentalDataViewStatus === 'error' ||
88+
(experimentalDataViewStatus === 'ready' && !experimentalDataView.hasMatchedIndices())
89+
: !oldSourcererDataViewSpec ||
90+
!oldSourcererDataViewSpec.id ||
91+
!oldSourcererDataViewSpec.title,
92+
[
93+
experimentalDataView,
94+
experimentalDataViewStatus,
95+
newDataViewPickerEnabled,
96+
oldSourcererDataViewSpec,
97+
]
98+
);
7199

72100
const { openPreviewPanel } = useExpandableFlyoutApi();
73101

@@ -89,7 +117,7 @@ export const AnalyzeGraph: FC = () => {
89117
);
90118
}
91119

92-
if (status === 'loading' || status === 'pristine') {
120+
if (isLoading) {
93121
return (
94122
<EuiFlexGroup gutterSize="m" justifyContent="center" alignItems="center">
95123
<EuiFlexItem grow={false}>
@@ -99,7 +127,7 @@ export const AnalyzeGraph: FC = () => {
99127
);
100128
}
101129

102-
if (status === 'error' || (status === 'ready' && !dataView.hasMatchedIndices())) {
130+
if (isDataViewInvalid) {
103131
return (
104132
<EuiEmptyPrompt
105133
color="danger"

0 commit comments

Comments
 (0)