Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cloud Security] [Misconfiguration] Add Grouping custom renderers #172256

Merged
merged 78 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
8bbb01a
wip: grouping
opauloh Oct 13, 2023
c40e2fc
group selector fix
opauloh Oct 17, 2023
0ac7e9e
WIP: group selector on findings page
opauloh Oct 17, 2023
bb7f308
adding more group by fields
opauloh Oct 18, 2023
1bacb6a
Merge branch 'main' into grouping/foundation
opauloh Oct 18, 2023
c9f251e
add non url additional filters
opauloh Oct 23, 2023
9432b87
Merge branch 'main' into grouping/foundation
opauloh Oct 23, 2023
4fd1510
adding custom title
opauloh Oct 25, 2023
fd4e071
additional filters
opauloh Oct 25, 2023
40a7797
datatable group component
opauloh Oct 25, 2023
bd80f34
clean up code
opauloh Oct 25, 2023
befa489
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Oct 25, 2023
2f761d5
add more information to disabled
opauloh Oct 25, 2023
ec0dbdf
code clean up
opauloh Oct 26, 2023
d55081c
hiding take action button
opauloh Oct 26, 2023
4d8e9bc
Merge branch 'main' into grouping/foundation
opauloh Nov 9, 2023
59cf7e3
addressing PR review suggestions
opauloh Nov 11, 2023
5abda98
splitting and optimizing code
opauloh Nov 13, 2023
dcde804
splitting code into hooks and components
opauloh Nov 13, 2023
97c19a3
addressing pr comments, removing anys
opauloh Nov 13, 2023
be967d2
findings grouping FTR tests
opauloh Nov 15, 2023
199f938
reverting change
opauloh Nov 15, 2023
f51a462
adding comments and time filtering
opauloh Nov 15, 2023
1af2377
revert use posture table
opauloh Nov 15, 2023
1eb9ef2
add use posture data table
opauloh Nov 15, 2023
a145184
update FTR tests
opauloh Nov 15, 2023
24188a3
Merge branch 'main' into grouping/foundation
opauloh Nov 15, 2023
975fd13
update dashboard navigation
opauloh Nov 15, 2023
1c0308c
fix ci errors
opauloh Nov 15, 2023
7bacb48
fixing ci and FTR tests
opauloh Nov 16, 2023
ca4713c
fix CI types error
opauloh Nov 16, 2023
95f8cf4
remove unused service from ftr
opauloh Nov 16, 2023
70e9539
Merge branch 'main' into grouping/foundation
opauloh Nov 21, 2023
2c35de7
Merge branch 'main' into grouping/foundation
opauloh Nov 21, 2023
3d866de
Merge branch 'main' into grouping/foundation
opauloh Nov 21, 2023
dca18ba
Merge branch 'main' into grouping/foundation
opauloh Nov 22, 2023
f3442d4
add abbr utils
opauloh Nov 22, 2023
dc766e4
table updates
opauloh Nov 22, 2023
9c82a65
grouping updates
opauloh Nov 22, 2023
f94e901
add custom renderers
opauloh Nov 22, 2023
ddb30ee
swap findings tabs
opauloh Nov 22, 2023
1db3905
compliance bar background
opauloh Nov 22, 2023
0a3a696
add isLoading to grouping renderer
opauloh Nov 22, 2023
8b34e14
add reverse compliance bar
opauloh Nov 22, 2023
ddebaf0
Merge branch 'main' into grouping/resource-custom-renderer
opauloh Nov 22, 2023
82493cf
reverting error handling
opauloh Nov 25, 2023
316a00f
implementing reset filters
opauloh Nov 25, 2023
e4b4bf8
adding test subjects
opauloh Nov 25, 2023
a4f8c29
add error handling
opauloh Nov 27, 2023
d793616
sorting groups by compliance score
opauloh Nov 27, 2023
166655f
custom non matching groups for cloud and kubernetes
opauloh Nov 27, 2023
af4d6b5
Merge branch 'main' into grouping/foundation
opauloh Nov 27, 2023
6ff86ab
adding maxGroupingLevels tests
opauloh Nov 27, 2023
249d1dd
Merge branch 'grouping/foundation' into grouping/resource-custom-rend…
opauloh Nov 27, 2023
a387104
Merge branch 'main' into grouping/resource-custom-renderer
opauloh Nov 28, 2023
ad6a3e8
fix wrong merge
opauloh Nov 29, 2023
9b74174
reverting isReverse prop
opauloh Nov 29, 2023
4466d43
translations
opauloh Nov 29, 2023
70b5c82
non matching group custom renderer
opauloh Nov 29, 2023
feea779
adding Distribution Bar Click handler
opauloh Nov 29, 2023
6e1a5f1
remove unused
opauloh Nov 29, 2023
378a013
revert isLoading
opauloh Nov 30, 2023
f316589
updating custom renderers css
opauloh Nov 30, 2023
c940a9d
wip updating ftr tests
opauloh Nov 30, 2023
56132e7
Merge branch 'main' into grouping/misconfigurations-custom-renderer
opauloh Nov 30, 2023
bab79e7
updating empty state component
opauloh Nov 30, 2023
cac60a1
adding more tests subjects
opauloh Nov 30, 2023
bab7688
updating FTR tests
opauloh Nov 30, 2023
c5e5a9c
fix ci checks, split utils hooks
opauloh Nov 30, 2023
950ddff
Merge branch 'main' into grouping/resource-custom-renderer
opauloh Dec 1, 2023
98fd861
Merge branch 'main' into grouping/resource-custom-renderer
opauloh Dec 1, 2023
9ef7cd2
unskipping FTR tests
opauloh Dec 1, 2023
93107f7
adding tests for get_abbreviated_number
opauloh Dec 1, 2023
97d30ee
updating constants to reflect field name
opauloh Dec 1, 2023
236a95d
added deprecation notice
opauloh Dec 1, 2023
189fc5e
update comments
opauloh Dec 1, 2023
ad489ed
updating constants
opauloh Dec 1, 2023
4d61f3f
code optimization / loading state
opauloh Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
*/

export * from './use_cloud_posture_data_table';
export * from './use_base_es_query';
export * from './use_persisted_query';
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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 { buildEsQuery, EsQueryConfig } from '@kbn/es-query';
import { i18n } from '@kbn/i18n';
import { useEffect, useMemo } from 'react';
import { FindingsBaseESQueryConfig, FindingsBaseProps, FindingsBaseURLQuery } from '../../types';
import { useKibana } from '../use_kibana';

const getBaseQuery = ({
dataView,
query,
filters,
config,
}: FindingsBaseURLQuery & FindingsBaseProps & FindingsBaseESQueryConfig) => {
try {
return {
query: buildEsQuery(dataView, query, filters, config), // will throw for malformed query
};
} catch (error) {
return {
query: undefined,
error: error instanceof Error ? error : new Error('Unknown Error'),
};
}
};

export const useBaseEsQuery = ({
dataView,
filters = [],
query,
nonPersistedFilters,
}: FindingsBaseURLQuery & FindingsBaseProps) => {
const {
notifications: { toasts },
data: {
query: { filterManager, queryString },
},
uiSettings,
} = useKibana().services;
const allowLeadingWildcards = uiSettings.get('query:allowLeadingWildcards');
const config: EsQueryConfig = useMemo(() => ({ allowLeadingWildcards }), [allowLeadingWildcards]);
const baseEsQuery = useMemo(
() =>
getBaseQuery({
dataView,
filters: filters.concat(nonPersistedFilters ?? []).flat(),
query,
config,
}),
[dataView, filters, nonPersistedFilters, query, config]
);

/**
* Sync filters with the URL query
*/
useEffect(() => {
filterManager.setAppFilters(filters);
queryString.setQuery(query);
}, [filters, filterManager, queryString, query]);

const handleMalformedQueryError = () => {
const error = baseEsQuery instanceof Error ? baseEsQuery : undefined;
if (error) {
toasts.addError(error, {
title: i18n.translate('xpack.csp.findings.search.queryErrorToastMessage', {
defaultMessage: 'Query Error',
}),
toastLifeTimeMs: 1000 * 5,
});
}
};

useEffect(handleMalformedQueryError, [baseEsQuery, toasts]);

return baseEsQuery;
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { CriteriaWithPagination } from '@elastic/eui';
import { DataTableRecord } from '@kbn/discover-utils/types';
import { useUrlQuery } from '../use_url_query';
import { usePageSize } from '../use_page_size';
import { getDefaultQuery, useBaseEsQuery, usePersistedQuery } from './utils';
import { getDefaultQuery } from './utils';
import { LOCAL_STORAGE_DATA_TABLE_COLUMNS_KEY } from '../../constants';
import { FindingsBaseURLQuery } from '../../types';
import { useBaseEsQuery } from './use_base_es_query';
import { usePersistedQuery } from './use_persisted_query';

type URLQuery = FindingsBaseURLQuery & Record<string, any>;

Expand Down Expand Up @@ -140,7 +142,16 @@ export const useCloudPostureDataTable = ({
setUrlQuery,
sort: urlQuery.sort,
filters: urlQuery.filters,
query: baseEsQuery.query,
query: baseEsQuery.query
? baseEsQuery.query
: {
bool: {
must: [],
filter: [],
should: [],
must_not: [],
},
},
queryError,
pageIndex: urlQuery.pageIndex,
urlQuery,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 { useCallback } from 'react';
import { type Query } from '@kbn/es-query';
import { FindingsBaseURLQuery } from '../../types';
import { useKibana } from '../use_kibana';

export const usePersistedQuery = <T>(getter: ({ filters, query }: FindingsBaseURLQuery) => T) => {
const {
data: {
query: { filterManager, queryString },
},
} = useKibana().services;

return useCallback(
() =>
getter({
filters: filterManager.getAppFilters(),
query: queryString.getQuery() as Query,
}),
[getter, filterManager, queryString]
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,7 @@
* 2.0.
*/

import { useEffect, useCallback, useMemo } from 'react';
import { buildEsQuery, EsQueryConfig } from '@kbn/es-query';
import type { EuiBasicTableProps, Pagination } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { type Query } from '@kbn/es-query';
import { useKibana } from '../use_kibana';
import type {
FindingsBaseESQueryConfig,
FindingsBaseProps,
FindingsBaseURLQuery,
} from '../../types';

const getBaseQuery = ({
dataView,
query,
filters,
config,
}: FindingsBaseURLQuery & FindingsBaseProps & FindingsBaseESQueryConfig) => {
try {
return {
query: buildEsQuery(dataView, query, filters, config), // will throw for malformed query
};
} catch (error) {
throw new Error(error);
}
};

type TablePagination = NonNullable<EuiBasicTableProps<unknown>['pagination']>;

Expand All @@ -52,74 +27,6 @@ export const getPaginationQuery = ({
size: pageSize,
});

export const useBaseEsQuery = ({
dataView,
filters = [],
query,
nonPersistedFilters,
}: FindingsBaseURLQuery & FindingsBaseProps) => {
const {
notifications: { toasts },
data: {
query: { filterManager, queryString },
},
uiSettings,
} = useKibana().services;
const allowLeadingWildcards = uiSettings.get('query:allowLeadingWildcards');
const config: EsQueryConfig = useMemo(() => ({ allowLeadingWildcards }), [allowLeadingWildcards]);
const baseEsQuery = useMemo(
() =>
getBaseQuery({
dataView,
filters: filters.concat(nonPersistedFilters ?? []).flat(),
query,
config,
}),
[dataView, filters, nonPersistedFilters, query, config]
);

/**
* Sync filters with the URL query
*/
useEffect(() => {
filterManager.setAppFilters(filters);
queryString.setQuery(query);
}, [filters, filterManager, queryString, query]);

const handleMalformedQueryError = () => {
const error = baseEsQuery instanceof Error ? baseEsQuery : undefined;
if (error) {
toasts.addError(error, {
title: i18n.translate('xpack.csp.findings.search.queryErrorToastMessage', {
defaultMessage: 'Query Error',
}),
toastLifeTimeMs: 1000 * 5,
});
}
};

useEffect(handleMalformedQueryError, [baseEsQuery, toasts]);

return baseEsQuery;
};

export const usePersistedQuery = <T>(getter: ({ filters, query }: FindingsBaseURLQuery) => T) => {
const {
data: {
query: { filterManager, queryString },
},
} = useKibana().services;

return useCallback(
() =>
getter({
filters: filterManager.getAppFilters(),
query: queryString.getQuery() as Query,
}),
[getter, filterManager, queryString]
);
};

export const getDefaultQuery = ({ query, filters }: any): any => ({
query,
filters,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { getAbbreviatedNumber } from './get_abbreviated_number';

describe('getAbbreviatedNumber', () => {
it('should return the same value if it is less than 1000', () => {
expect(getAbbreviatedNumber(0)).toBe(0);
expect(getAbbreviatedNumber(1)).toBe(1);
expect(getAbbreviatedNumber(500)).toBe(500);
expect(getAbbreviatedNumber(999)).toBe(999);
});

it('should use numeral to format the value if it is greater than or equal to 1000', () => {
expect(getAbbreviatedNumber(1000)).toBe('1.0k');

expect(getAbbreviatedNumber(1200)).toBe('1.2k');

expect(getAbbreviatedNumber(3500000)).toBe('3.5m');

expect(getAbbreviatedNumber(2800000000)).toBe('2.8b');

expect(getAbbreviatedNumber(5900000000000)).toBe('5.9t');

expect(getAbbreviatedNumber(59000000000000000)).toBe('59000.0t');
});

it('should return 0 if the value is NaN', () => {
expect(getAbbreviatedNumber(NaN)).toBe(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 numeral from '@elastic/numeral';

/**
* Returns an abbreviated number when the value is greater than or equal to 1000.
* The abbreviated number is formatted using numeral:
* - thousand: k
* - million: m
* - billion: b
* - trillion: t
* */
export const getAbbreviatedNumber = (value: number) => {
if (isNaN(value)) {
return 0;
}
return value < 1000 ? value : numeral(value).format('0.0a');
opauloh marked this conversation as resolved.
Show resolved Hide resolved
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@ import React, { useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty, EuiFlexItem } from '@elastic/eui';
import { type DataView } from '@kbn/data-views-plugin/common';
import numeral from '@elastic/numeral';
import { FieldsSelectorModal } from './fields_selector';
import { useStyles } from './use_styles';

const formatNumber = (value: number) => {
return value < 1000 ? value : numeral(value).format('0.0a');
};
import { getAbbreviatedNumber } from '../../common/utils/get_abbreviated_number';

const GroupSelectorWrapper: React.FC = ({ children }) => {
const styles = useStyles();
Expand Down Expand Up @@ -60,7 +56,7 @@ export const AdditionalControls = ({
/>
)}
<EuiFlexItem grow={0}>
<span className="cspDataTableTotal">{`${formatNumber(total)} ${title}`}</span>
<span className="cspDataTableTotal">{`${getAbbreviatedNumber(total)} ${title}`}</span>
</EuiFlexItem>
<EuiFlexItem grow={0}>
<EuiButtonEmpty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ export const useStyles = () => {
`;

const groupBySelector = css`
width: 188px;
margin-left: auto;
`;

Expand Down
Loading
Loading