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

Added pagination to SCA table #4653

Merged
merged 13 commits into from
Oct 19, 2022
Merged
106 changes: 38 additions & 68 deletions public/components/agents/sca/inventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
EuiPanel,
EuiPage,
EuiBasicTable,
EuiInMemoryTable,
EuiSpacer,
EuiText,
EuiProgress,
Expand Down Expand Up @@ -49,7 +48,8 @@ import {
import { API_NAME_AGENT_STATUS, UI_LOGGER_LEVELS } from '../../../../common/constants';
import { getErrorOrchestrator } from '../../../react-services/common-services';
import { VisualizationBasic } from '../../common/charts/visualizations/basic';

import { TableWzAPI } from '../../common/tables';
import { getFilterValues } from './lib/api-request';
export class Inventory extends Component {
_isMount = false;
constructor(props) {
Expand All @@ -70,32 +70,39 @@ export class Inventory extends Component {
{
field: 'name',
name: 'Policy',
sortable: true,
},
{
field: 'description',
name: 'Description',
truncateText: true,
render: formatUIDate,
sortable: true,
},
{
field: 'end_scan',
name: 'End scan',
dataType: 'date',
render: formatUIDate,
sortable: true,
},
{
field: 'pass',
name: 'Pass',
width: '100px',
sortable: true,
},
{
field: 'fail',
name: 'Fail',
width: '100px',
sortable: true,
},
{
field: 'invalid',
name: 'Not applicable',
width: '100px',
sortable: true,
},
{
field: 'score',
Expand Down Expand Up @@ -265,95 +272,82 @@ export class Inventory extends Component {
});
});

/**
* Get list of values defined in distinctFields by field
* @param value
* @param field
* @returns
*/
const getSuggestionsValues = (value, field) => {
if (!distinctFields[field]) return [];
return Object.keys(distinctFields[field]).filter(
(item) => item && item.toLowerCase().includes(value.toLowerCase().trim())
);
};

/**
* Get list of suggestions.
* This method validate if the suggestion item exists in the checks array fields
* @returns List of suggestions
*/
const getSuggestionsFields = () => {
const getSuggestionsFields = (policy) => {
const defaultSuggestions = [
{
type: 'params',
label: 'condition',
description: 'Filter by check condition',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'condition'),
values: (value) => getFilterValues('condition', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'file',
description: 'Filter by check file',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'file'),
values: (value) => getFilterValues('file', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'title',
description: 'Filter by check title',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'title'),
values: (value) => getFilterValues('title', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'result',
description: 'Filter by check result',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'result'),
values: (value) => getFilterValues('result', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'status',
description: 'Filter by check status',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'status'),
values: (value) => getFilterValues('status', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'rationale',
description: 'Filter by check rationale',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'rationale'),
values: (value) => getFilterValues('rationale', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'registry',
description: 'Filter by check registry',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'registry'),
values: (value) => getFilterValues('registry', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'description',
description: 'Filter by check description',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'description'),
values: (value) => getFilterValues('description', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'remediation',
description: 'Filter by check remediation',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'remediation'),
values: (value) => getFilterValues('remediation', value, this.props.agent.id, policy),
},
{
type: 'params',
label: 'reason',
description: 'Filter by check reason',
operators: ['=', '!='],
values: (value) => getSuggestionsValues(value, 'reason'),
values: (value) => getFilterValues('reason', value, this.props.agent.id, policy),
},
];

Expand All @@ -363,7 +357,7 @@ export class Inventory extends Component {
return filteresSuggestions;
};

this.suggestions[policy] = getSuggestionsFields();
this.suggestions[policy] = getSuggestionsFields(policy);
}

async initialize() {
Expand Down Expand Up @@ -441,23 +435,6 @@ export class Inventory extends Component {
}
}

filterPolicyChecks = () =>
!!this.state.items &&
this.state.items.filter((check) =>
this.state.filters.every((filter) =>
filter.field === 'search'
? Object.keys(check).some(
(key) =>
['string', 'number'].includes(typeof check[key]) &&
String(check[key]).toLowerCase().includes(filter.value.toLowerCase())
)
: typeof check[filter.field] === 'string' &&
(filter.value === ''
? check[filter.field] === filter.value
: check[filter.field].toLowerCase().includes(filter.value.toLowerCase()))
)
);

toggleDetails = (item) => {
const itemIdToExpandedRowMap = { ...this.state.itemIdToExpandedRowMap };

Expand Down Expand Up @@ -775,33 +752,26 @@ export class Inventory extends Component {
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />

<EuiFlexGroup>
<EuiFlexItem>
<WzSearchBar
filters={this.state.filters}
suggestions={this.suggestions[this.state.lookingPolicy.policy_id]}
placeholder="Filter or search"
onFiltersChange={(filters) => {
this.setState({ filters });
}}
/>
</EuiFlexItem>
</EuiFlexGroup>

<EuiFlexGroup>
<EuiFlexItem>
<EuiInMemoryTable
items={this.filterPolicyChecks()}
columns={this.columnsChecks}
<TableWzAPI
title="Checks"
tableColumns={this.columnsChecks}
tableInitialSortingField="id"
searchTable={true}
searchBarSuggestions={this.suggestions[this.state.lookingPolicy.policy_id]}
endpoint={`/sca/${this.props.agent.id}/checks/${this.state.lookingPolicy.policy_id}`}
rowProps={getChecksRowProps}
itemId="id"
itemIdToExpandedRowMap={this.state.itemIdToExpandedRowMap}
isExpandable={true}
sorting={sorting}
pagination={this.state.pageTableChecks}
loading={this.state.loadingPolicy}
onTableChange={(change) => this.onChangeTableChecks(change)}
tableProps={{
isExpandable: true,
itemIdToExpandedRowMap: this.state.itemIdToExpandedRowMap,
itemId: 'id',
}}
downloadCsv
showReload
filters={this.state.filters}
onFiltersChange={(filters) => this.setState({ filters })}
tablePageSizeOptions={[10, 25, 50, 100]}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
28 changes: 28 additions & 0 deletions public/components/agents/sca/lib/api-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { WzRequest } from '../../../../react-services/wz-request';

export async function getFilterValues(
field,
value,
agentId,
policyId,
filters = {},
format = (item) => item
) {
const filter = {
...filters,
distinct: true,
select: field,
limit: 30,
};
if (value) {
filter['search'] = value;
}
const result = await WzRequest.apiReq('GET', `/sca/${agentId}/checks/${policyId}`, {
params: filter,
});
return (
result?.data?.data?.affected_items?.map((item) => {
return format(item[field]);
}) || []
);
}
Loading