Skip to content

Commit 4569889

Browse files
move fetching rules within sources hook
1 parent 58dc672 commit 4569889

4 files changed

Lines changed: 118 additions & 56 deletions

File tree

x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/search_bar/search_bar_section.test.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,18 @@ import {
1414
SearchBarSection,
1515
SOURCE_BUTTON_LOADING_TEST_ID,
1616
} from './search_bar_section';
17-
import { useFindRulesQuery } from '../../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
1817
import type { DataView } from '@kbn/data-views-plugin/common';
1918
import { createStubDataView } from '@kbn/data-views-plugin/common/data_views/data_view.stub';
2019
import { SOURCE_BUTTON_TEST_ID } from './sources_filter_button';
2120
import { useKibana } from '../../../../common/lib/kibana';
22-
import { useSources } from '../../../hooks/alert_summary/use_get_sources';
21+
import { useSources } from '../../../hooks/alert_summary/use_sources';
2322

2423
jest.mock('../../../../common/components/search_bar', () => ({
2524
// The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables so we can't use SEARCH_BAR_TEST_ID
2625
SiemSearchBar: () => <div data-test-subj={'alert-summary-search-bar'} />,
2726
}));
28-
jest.mock('../../../../detection_engine/rule_management/api/hooks/use_find_rules_query');
2927
jest.mock('../../../../common/lib/kibana');
30-
jest.mock('../../../hooks/alert_summary/use_get_sources');
28+
jest.mock('../../../hooks/alert_summary/use_sources');
3129

3230
const dataView: DataView = createStubDataView({ spec: {} });
3331
const packages: PackageListItem[] = [
@@ -42,10 +40,10 @@ const packages: PackageListItem[] = [
4240

4341
describe('<SearchBarSection />', () => {
4442
it('should render all components', () => {
45-
(useFindRulesQuery as jest.Mock).mockReturnValue({
43+
(useSources as jest.Mock).mockReturnValue({
4644
isLoading: false,
45+
sources: [],
4746
});
48-
(useSources as jest.Mock).mockReturnValue([]);
4947
(useKibana as jest.Mock).mockReturnValue({
5048
services: { data: { query: { filterManager: jest.fn() } } },
5149
});
@@ -60,10 +58,10 @@ describe('<SearchBarSection />', () => {
6058
});
6159

6260
it('should render a loading skeleton for the source button while fetching rules', () => {
63-
(useFindRulesQuery as jest.Mock).mockReturnValue({
61+
(useSources as jest.Mock).mockReturnValue({
6462
isLoading: true,
63+
sources: [],
6564
});
66-
(useSources as jest.Mock).mockReturnValue([]);
6765

6866
const { getByTestId, queryByTestId } = render(
6967
<SearchBarSection dataView={dataView} packages={packages} />

x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/search_bar/search_bar_section.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import React, { memo, useMemo } from 'react';
99
import type { DataView } from '@kbn/data-views-plugin/common';
1010
import { EuiFlexGroup, EuiFlexItem, EuiSkeletonRectangle } from '@elastic/eui';
1111
import type { PackageListItem } from '@kbn/fleet-plugin/common';
12-
import { useSources } from '../../../hooks/alert_summary/use_get_sources';
13-
import { useFindRulesQuery } from '../../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
12+
import { useSources } from '../../../hooks/alert_summary/use_sources';
1413
import { SiemSearchBar } from '../../../../common/components/search_bar';
1514
import { SourceFilterButton } from './sources_filter_button';
1615
import { InputsModelId } from '../../../../common/store/inputs/constants';
@@ -40,8 +39,7 @@ export interface SearchBarSectionProps {
4039
* This means that deselecting a source is equivalent to filtering out by the rule for that integration.
4140
*/
4241
export const SearchBarSection = memo(({ dataView, packages }: SearchBarSectionProps) => {
43-
const { data, isLoading } = useFindRulesQuery({});
44-
const sources = useSources({ packages, ruleResponse: data });
42+
const { isLoading, sources } = useSources({ packages });
4543

4644
const dataViewSpec = useMemo(() => dataView.toSpec(), [dataView]);
4745

x-pack/solutions/security/plugins/security_solution/public/detections/hooks/alert_summary/use_get_sources.test.ts renamed to x-pack/solutions/security/plugins/security_solution/public/detections/hooks/alert_summary/use_sources.test.ts

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
*/
77

88
import { renderHook } from '@testing-library/react';
9-
import { useSources } from './use_get_sources';
9+
import { useSources } from './use_sources';
1010
import { useKibana } from '../../../common/lib/kibana';
1111
import type { PackageListItem } from '@kbn/fleet-plugin/common';
1212
import { installationStatuses } from '@kbn/fleet-plugin/common/constants';
13-
import type { RulesQueryResponse } from '../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
13+
import { useFindRulesQuery } from '../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
1414
import { FILTER_KEY } from '../../components/alert_summary/search_bar/sources_filter_button';
1515

1616
jest.mock('../../../common/lib/kibana');
17+
jest.mock('../../../detection_engine/rule_management/api/hooks/use_find_rules_query');
1718

1819
describe('useSources', () => {
1920
beforeEach(() => {
@@ -32,6 +33,18 @@ describe('useSources', () => {
3233
},
3334
},
3435
});
36+
(useFindRulesQuery as jest.Mock).mockReturnValue({
37+
isLoading: false,
38+
data: {
39+
rules: [
40+
{
41+
related_integrations: [{ package: 'splunk' }],
42+
name: 'SplunkRuleName',
43+
},
44+
],
45+
total: 0,
46+
},
47+
});
3548

3649
const packages: PackageListItem[] = [
3750
{
@@ -42,26 +55,20 @@ describe('useSources', () => {
4255
version: '',
4356
},
4457
];
45-
const ruleResponse = {
46-
rules: [
58+
59+
const { result } = renderHook(() => useSources({ packages }));
60+
61+
expect(result.current).toEqual({
62+
isLoading: false,
63+
sources: [
4764
{
48-
related_integrations: [{ package: 'splunk' }],
49-
name: 'SplunkRuleName',
65+
checked: 'on',
66+
'data-test-subj': 'alert-summary-source-option-Splunk',
67+
key: 'SplunkRuleName',
68+
label: 'Splunk',
5069
},
5170
],
52-
total: 0,
53-
} as unknown as RulesQueryResponse;
54-
55-
const { result } = renderHook(() => useSources({ packages, ruleResponse }));
56-
57-
expect(result.current).toEqual([
58-
{
59-
checked: 'on',
60-
'data-test-subj': 'alert-summary-source-option-Splunk',
61-
key: 'SplunkRuleName',
62-
label: 'Splunk',
63-
},
64-
]);
71+
});
6572
});
6673

6774
it('should return an un-checked source', () => {
@@ -88,6 +95,18 @@ describe('useSources', () => {
8895
},
8996
},
9097
});
98+
(useFindRulesQuery as jest.Mock).mockReturnValue({
99+
isLoading: false,
100+
data: {
101+
rules: [
102+
{
103+
related_integrations: [{ package: 'splunk' }],
104+
name: 'SplunkRuleName',
105+
},
106+
],
107+
total: 0,
108+
},
109+
});
91110

92111
const packages: PackageListItem[] = [
93112
{
@@ -98,33 +117,60 @@ describe('useSources', () => {
98117
version: '',
99118
},
100119
];
101-
const ruleResponse = {
102-
rules: [
120+
121+
const { result } = renderHook(() => useSources({ packages }));
122+
123+
expect(result.current).toEqual({
124+
isLoading: false,
125+
sources: [
103126
{
104-
related_integrations: [{ package: 'splunk' }],
105-
name: 'SplunkRuleName',
127+
'data-test-subj': 'alert-summary-source-option-Splunk',
128+
key: 'SplunkRuleName',
129+
label: 'Splunk',
106130
},
107131
],
108-
total: 0,
109-
} as unknown as RulesQueryResponse;
132+
});
133+
});
110134

111-
const { result } = renderHook(() => useSources({ packages, ruleResponse }));
135+
it('should not return a source if no rule match', () => {
136+
(useKibana as jest.Mock).mockReturnValue({
137+
services: {
138+
data: { query: { filterManager: { getFilters: jest.fn().mockReturnValue([]) } } },
139+
},
140+
});
141+
(useFindRulesQuery as jest.Mock).mockReturnValue({
142+
isLoading: false,
143+
data: undefined,
144+
});
112145

113-
expect(result.current).toEqual([
146+
const packages: PackageListItem[] = [
114147
{
115-
'data-test-subj': 'alert-summary-source-option-Splunk',
116-
key: 'SplunkRuleName',
117-
label: 'Splunk',
148+
id: 'splunk',
149+
name: 'splunk',
150+
status: installationStatuses.Installed,
151+
title: 'Splunk',
152+
version: '',
118153
},
119-
]);
154+
];
155+
156+
const { result } = renderHook(() => useSources({ packages }));
157+
158+
expect(result.current).toEqual({
159+
isLoading: false,
160+
sources: [],
161+
});
120162
});
121163

122-
it('should not return a source if no rule match', () => {
164+
it('should return isLoading true if rules are loading', () => {
123165
(useKibana as jest.Mock).mockReturnValue({
124166
services: {
125167
data: { query: { filterManager: { getFilters: jest.fn().mockReturnValue([]) } } },
126168
},
127169
});
170+
(useFindRulesQuery as jest.Mock).mockReturnValue({
171+
isLoading: true,
172+
data: undefined,
173+
});
128174

129175
const packages: PackageListItem[] = [
130176
{
@@ -135,10 +181,12 @@ describe('useSources', () => {
135181
version: '',
136182
},
137183
];
138-
const ruleResponse = undefined;
139184

140-
const { result } = renderHook(() => useSources({ packages, ruleResponse }));
185+
const { result } = renderHook(() => useSources({ packages }));
141186

142-
expect(result.current).toHaveLength(0);
187+
expect(result.current).toEqual({
188+
isLoading: true,
189+
sources: [],
190+
});
143191
});
144192
});

x-pack/solutions/security/plugins/security_solution/public/detections/hooks/alert_summary/use_get_sources.ts renamed to x-pack/solutions/security/plugins/security_solution/public/detections/hooks/alert_summary/use_sources.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {
1111
EuiSelectableOption,
1212
EuiSelectableOptionCheckedType,
1313
} from '@elastic/eui/src/components/selectable/selectable_option';
14-
import type { RulesQueryResponse } from '../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
14+
import { useFindRulesQuery } from '../../../detection_engine/rule_management/api/hooks/use_find_rules_query';
1515
import { filterExistsInFiltersArray } from '../../utils/filter';
1616
import { useKibana } from '../../../common/lib/kibana';
1717
import type { RuleResponse } from '../../../../common/api/detection_engine';
@@ -24,32 +24,42 @@ export interface UseSourcesParams {
2424
* List of installed AI for SOC integrations
2525
*/
2626
packages: PackageListItem[];
27+
}
28+
29+
export interface UseSourcesResult {
30+
/**
31+
* True while rules are being fetched
32+
*/
33+
isLoading: boolean;
2734
/**
28-
* All rules
35+
* List of sources ready to be consumed by the SourceFilterButton component
2936
*/
30-
ruleResponse: RulesQueryResponse | undefined;
37+
sources: EuiSelectableOption[];
3138
}
3239

3340
/**
3441
* Combining installed packages and rules to create an interface that the SourceFilterButton can take as input (as EuiSelectableOption).
35-
* If there is not match between a package and the rules, the source is not returned.
42+
* If there is no match between a package and the rules, the source is not returned.
3643
* If a filter exists (we assume that this filter is negated) we do not mark the source as checked for the EuiFilterButton.
3744
*/
38-
export const useSources = ({ packages, ruleResponse }: UseSourcesParams): EuiSelectableOption[] => {
45+
export const useSources = ({ packages }: UseSourcesParams): UseSourcesResult => {
46+
// Fetch all rules. For the AI for SOC effort, there should only be one rule per integration (which means for now 5-6 rules total)
47+
const { data, isLoading } = useFindRulesQuery({});
48+
3949
const {
4050
data: {
4151
query: { filterManager },
4252
},
4353
} = useKibana().services;
4454

45-
// There can be existing filters coming from the url
55+
// There can be existing rules filtered out, coming when parsing the url
4656
const currentFilters = filterManager.getFilters();
4757

48-
return useMemo(() => {
58+
const sources = useMemo(() => {
4959
const result: EuiSelectableOption[] = [];
5060

5161
packages.forEach((p: PackageListItem) => {
52-
const matchingRule = (ruleResponse?.rules || []).find((r: RuleResponse) =>
62+
const matchingRule = (data?.rules || []).find((r: RuleResponse) =>
5363
r.related_integrations.map((ri) => ri.package).includes(p.name)
5464
);
5565

@@ -69,5 +79,13 @@ export const useSources = ({ packages, ruleResponse }: UseSourcesParams): EuiSel
6979
});
7080

7181
return result;
72-
}, [currentFilters, packages, ruleResponse]);
82+
}, [currentFilters, data, packages]);
83+
84+
return useMemo(
85+
() => ({
86+
isLoading,
87+
sources,
88+
}),
89+
[isLoading, sources]
90+
);
7391
};

0 commit comments

Comments
 (0)