mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Cloud Posture] fix negated filter in findings (#137021)
This commit is contained in:
parent
0cc899cdb0
commit
e33f4b0f80
6 changed files with 129 additions and 41 deletions
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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 { CSP_LATEST_FINDINGS_DATA_VIEW } from '../../../common/constants';
|
||||
import { createStubDataView } from '@kbn/data-views-plugin/common/stubs';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { getFilters } from './get_filters';
|
||||
|
||||
describe('Get Filters', () => {
|
||||
let dataViewMock: DataView;
|
||||
const fieldKey = 'some_field_name';
|
||||
|
||||
beforeEach(() => {
|
||||
dataViewMock = createStubDataView({
|
||||
spec: {
|
||||
id: CSP_LATEST_FINDINGS_DATA_VIEW,
|
||||
fields: {
|
||||
a: {
|
||||
searchable: false,
|
||||
aggregatable: false,
|
||||
name: fieldKey,
|
||||
type: 'type',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('negate an existing filter', () => {
|
||||
const fields = {
|
||||
dataView: dataViewMock,
|
||||
field: fieldKey,
|
||||
value: 'b',
|
||||
};
|
||||
const initialFilters = getFilters({
|
||||
...fields,
|
||||
filters: [],
|
||||
negate: false,
|
||||
});
|
||||
|
||||
expect(initialFilters.length).toBe(1);
|
||||
expect(initialFilters[0].meta.negate).toBe(false);
|
||||
|
||||
const nextFilters = getFilters({
|
||||
...fields,
|
||||
filters: initialFilters,
|
||||
negate: true,
|
||||
});
|
||||
|
||||
expect(nextFilters.length).toBe(1);
|
||||
expect(nextFilters[0].meta.negate).toBe(true);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 Filter,
|
||||
buildFilter,
|
||||
FILTERS,
|
||||
FilterStateStore,
|
||||
compareFilters,
|
||||
FilterCompareOptions,
|
||||
} from '@kbn/es-query';
|
||||
import type { Serializable } from '@kbn/utility-types';
|
||||
import type { FindingsBaseProps } from './types';
|
||||
|
||||
const compareOptions: FilterCompareOptions = {
|
||||
negate: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* adds a new filter to a new filters array
|
||||
* removes existing filter if negated filter is added
|
||||
*
|
||||
* @returns {Filter[]} a new array of filters to be added back to filterManager
|
||||
*/
|
||||
export const getFilters = ({
|
||||
filters: existingFilters,
|
||||
dataView,
|
||||
field,
|
||||
value,
|
||||
negate,
|
||||
}: {
|
||||
filters: Filter[];
|
||||
dataView: FindingsBaseProps['dataView'];
|
||||
field: string;
|
||||
value: Serializable;
|
||||
negate: boolean;
|
||||
}): Filter[] => {
|
||||
const dataViewField = dataView.getFieldByName(field);
|
||||
if (!dataViewField) return existingFilters;
|
||||
|
||||
const phraseFilter = buildFilter(
|
||||
dataView,
|
||||
dataViewField,
|
||||
FILTERS.PHRASE,
|
||||
negate,
|
||||
false,
|
||||
value,
|
||||
null,
|
||||
FilterStateStore.APP_STATE
|
||||
);
|
||||
|
||||
const nextFilters = [
|
||||
...existingFilters.filter(
|
||||
// Exclude existing filters that match the newly added 'phraseFilter'
|
||||
(filter) => !compareFilters(filter, phraseFilter, compareOptions)
|
||||
),
|
||||
phraseFilter,
|
||||
];
|
||||
|
||||
return nextFilters;
|
||||
};
|
|
@ -18,7 +18,7 @@ import type { FindingsBaseURLQuery } from '../types';
|
|||
import { FindingsDistributionBar } from '../layout/findings_distribution_bar';
|
||||
import {
|
||||
getFindingsPageSizeInfo,
|
||||
addFilter,
|
||||
getFilters,
|
||||
getPaginationQuery,
|
||||
getPaginationTableParams,
|
||||
useBaseEsQuery,
|
||||
|
@ -119,7 +119,7 @@ export const LatestFindingsContainer = ({ dataView }: FindingsBaseProps) => {
|
|||
onAddFilter={(field, value, negate) =>
|
||||
setUrlQuery({
|
||||
pageIndex: 0,
|
||||
filters: addFilter({
|
||||
filters: getFilters({
|
||||
filters: urlQuery.filters,
|
||||
dataView,
|
||||
field,
|
||||
|
|
|
@ -17,7 +17,7 @@ import { FindingsByResourceQuery, useFindingsByResource } from './use_findings_b
|
|||
import { FindingsByResourceTable } from './findings_by_resource_table';
|
||||
import {
|
||||
getFindingsPageSizeInfo,
|
||||
addFilter,
|
||||
getFilters,
|
||||
getPaginationQuery,
|
||||
getPaginationTableParams,
|
||||
useBaseEsQuery,
|
||||
|
@ -143,7 +143,7 @@ const LatestFindingsByResource = ({ dataView }: FindingsBaseProps) => {
|
|||
onAddFilter={(field, value, negate) =>
|
||||
setUrlQuery({
|
||||
pageIndex: 0,
|
||||
filters: addFilter({
|
||||
filters: getFilters({
|
||||
filters: urlQuery.filters,
|
||||
dataView,
|
||||
field,
|
||||
|
|
|
@ -19,7 +19,7 @@ import { useUrlQuery } from '../../../../common/hooks/use_url_query';
|
|||
import type { FindingsBaseURLQuery, FindingsBaseProps, CspFinding } from '../../types';
|
||||
import {
|
||||
getFindingsPageSizeInfo,
|
||||
addFilter,
|
||||
getFilters,
|
||||
getPaginationQuery,
|
||||
getPaginationTableParams,
|
||||
useBaseEsQuery,
|
||||
|
@ -147,7 +147,7 @@ export const ResourceFindings = ({ dataView }: FindingsBaseProps) => {
|
|||
onAddFilter={(field, value, negate) =>
|
||||
setUrlQuery({
|
||||
pageIndex: 0,
|
||||
filters: addFilter({
|
||||
filters: getFilters({
|
||||
filters: urlQuery.filters,
|
||||
dataView,
|
||||
field,
|
||||
|
|
|
@ -5,15 +5,14 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { buildEsQuery, type Filter, buildFilter, FILTERS, FilterStateStore } from '@kbn/es-query';
|
||||
import { buildEsQuery } from '@kbn/es-query';
|
||||
import { EuiBasicTableProps, Pagination } from '@elastic/eui';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import type { Serializable } from '@kbn/utility-types';
|
||||
import type { FindingsBaseProps, FindingsBaseURLQuery } from './types';
|
||||
import { useKibana } from '../../common/hooks/use_kibana';
|
||||
import { isNonNullable } from '../../../common/utils/helpers';
|
||||
export { getFilters } from './get_filters';
|
||||
|
||||
const getBaseQuery = ({ dataView, query, filters }: FindingsBaseURLQuery & FindingsBaseProps) => {
|
||||
try {
|
||||
|
@ -130,38 +129,6 @@ export const getAggregationCount = (buckets: estypes.AggregationsStringRareTerms
|
|||
};
|
||||
};
|
||||
|
||||
export const addFilter = ({
|
||||
filters,
|
||||
dataView,
|
||||
field,
|
||||
value,
|
||||
negate,
|
||||
}: {
|
||||
filters: Filter[];
|
||||
dataView: FindingsBaseProps['dataView'];
|
||||
field: string;
|
||||
value: Serializable;
|
||||
negate: boolean;
|
||||
}): Filter[] => {
|
||||
const dataViewField = dataView.getFieldByName(field);
|
||||
if (!dataViewField) return filters;
|
||||
|
||||
const singleValue = Array.isArray(value) ? value[0] : value;
|
||||
|
||||
const filter = buildFilter(
|
||||
dataView,
|
||||
dataViewField,
|
||||
FILTERS.PHRASE,
|
||||
negate,
|
||||
false,
|
||||
singleValue,
|
||||
null,
|
||||
FilterStateStore.APP_STATE
|
||||
);
|
||||
|
||||
return [...filters, filter].filter(isNonNullable);
|
||||
};
|
||||
|
||||
const FIELDS_WITHOUT_KEYWORD_MAPPING = new Set([
|
||||
'@timestamp',
|
||||
'resource.sub_type',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue