diff --git a/public/components/agents/sca/inventory.tsx b/public/components/agents/sca/inventory.tsx
index d0da6affd3..02e0ea576b 100644
--- a/public/components/agents/sca/inventory.tsx
+++ b/public/components/agents/sca/inventory.tsx
@@ -36,7 +36,7 @@ import {
import { WzRequest } from '../../../react-services/wz-request';
import { formatUIDate } from '../../../react-services/time-service';
import exportCsv from '../../../react-services/wz-csv';
-import { getToasts } from '../../../kibana-services';
+import { getToasts } from '../../../kibana-services';
import { WzSearchBar } from '../../../components/wz-search-bar';
import { RuleText, ComplianceText } from './components';
import _ from 'lodash';
@@ -55,46 +55,55 @@ export class Inventory extends Component {
constructor(props) {
super(props);
const { agent } = this.props;
- this.state = { agent, items: [], itemIdToExpandedRowMap: {}, showMoreInfo: false, loading: false, filters: [], pageTableChecks: {pageIndex: 0}, policies: [] }
+ this.state = {
+ agent,
+ items: [],
+ itemIdToExpandedRowMap: {},
+ showMoreInfo: false,
+ loading: false,
+ filters: [],
+ pageTableChecks: { pageIndex: 0 },
+ policies: [],
+ };
this.suggestions = {};
this.columnsPolicies = [
{
field: 'name',
- name: 'Policy'
+ name: 'Policy',
},
{
field: 'description',
name: 'Description',
- truncateText: true
+ truncateText: true,
},
{
field: 'end_scan',
name: 'End scan',
dataType: 'date',
- render: formatUIDate
+ render: formatUIDate,
},
{
field: 'pass',
name: 'Pass',
- width: "100px"
+ width: '100px',
},
{
field: 'fail',
name: 'Fail',
- width: "100px"
+ width: '100px',
},
{
field: 'invalid',
name: 'Not applicable',
- width: "100px"
+ width: '100px',
},
{
field: 'score',
name: 'Score',
- render: score => {
+ render: (score) => {
return `${score}%`;
},
- width: "100px"
+ width: '100px',
},
];
this.columnsChecks = [
@@ -102,18 +111,18 @@ export class Inventory extends Component {
field: 'id',
name: 'ID',
sortable: true,
- width: "100px"
+ width: '100px',
},
{
field: 'title',
name: 'Title',
sortable: true,
- truncateText: true
+ truncateText: true,
},
{
name: 'Target',
truncateText: true,
- render: item => (
+ render: (item) => (
{item.file ? (
@@ -136,37 +145,31 @@ export class Inventory extends Component {
Registry: {item.registry}
) : (
- '-'
- )}
+ '-'
+ )}
- )
+ ),
},
{
field: 'result',
name: 'Result',
truncateText: true,
sortable: true,
- width: "150px",
+ width: '150px',
render: this.addHealthResultRender,
},
{
align: 'right',
- width: "40px",
+ width: '40px',
isExpander: true,
- render: item => (
+ render: (item) => (
this.toggleDetails(item)}
- aria-label={
- this.state.itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'
- }
- iconType={
- this.state.itemIdToExpandedRowMap[item.id]
- ? 'arrowUp'
- : 'arrowDown'
- }
+ aria-label={this.state.itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'}
+ iconType={this.state.itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'}
/>
- )
- }
+ ),
+ },
];
}
@@ -179,13 +182,14 @@ export class Inventory extends Component {
if (match && match[0]) {
this.setState({ loading: true });
const id = match[0].split('=')[1];
- const policy = await WzRequest.apiReq(
- 'GET',
- `/sca/${this.props.agent.id}`,
- { "q": "policy_id=" + id }
- );
+ const policy = await WzRequest.apiReq('GET', `/sca/${this.props.agent.id}`, {
+ q: 'policy_id=' + id,
+ });
await this.loadScaPolicy(((((policy || {}).data || {}).data || {}).items || [])[0]);
- window.location.href = window.location.href.replace(new RegExp('redirectPolicy=' + '[^&]*'), '');
+ window.location.href = window.location.href.replace(
+ new RegExp('redirectPolicy=' + '[^&]*'),
+ ''
+ );
this.setState({ loading: false });
}
} catch (error) {
@@ -208,9 +212,12 @@ export class Inventory extends Component {
async componentDidUpdate(prevProps, prevState) {
if (!_.isEqual(this.props.agent, prevProps.agent)) {
this.setState({ lookingPolicy: false }, async () => await this.initialize());
- };
- if(!_.isEqual(this.state.filters, prevState.filters)){
- this.setState({itemIdToExpandedRowMap: {}, pageTableChecks: {pageIndex: 0, pageSize: this.state.pageTableChecks.pageSize}});
+ }
+ if (!_.isEqual(this.state.filters, prevState.filters)) {
+ this.setState({
+ itemIdToExpandedRowMap: {},
+ pageTableChecks: { pageIndex: 0, pageSize: this.state.pageTableChecks.pageSize },
+ });
}
}
@@ -219,7 +226,7 @@ export class Inventory extends Component {
}
addHealthResultRender(result) {
- const color = result => {
+ const color = (result) => {
if (result.toLowerCase() === 'passed') {
return 'success';
} else if (result.toLowerCase() === 'failed') {
@@ -236,11 +243,17 @@ export class Inventory extends Component {
);
}
+ /**
+ * Generate and assign the suggestions for the searchbar
+ * @param policy
+ * @param checks
+ * @returns
+ */
buildSuggestionSearchBar(policy, checks) {
if (this.suggestions[policy]) return;
const distinctFields = {};
- checks.forEach(item => {
- Object.keys(item).forEach(field => {
+ checks.forEach((item) => {
+ Object.keys(item).forEach((field) => {
if (typeof item[field] === 'string') {
if (!distinctFields[field]) {
distinctFields[field] = {};
@@ -252,33 +265,119 @@ export class Inventory extends Component {
});
});
- this.suggestions[policy] = [
- { type: 'params', label: 'condition', description: 'Filter by check condition', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["condition"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'file', description: 'Filter by check file', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["file"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'title', description: 'Filter by check title', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["title"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'result', description: 'Filter by check result', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["result"]).filter(item => item && item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'status', description: 'Filter by check status', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["status"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'rationale', description: 'Filter by check rationale', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["rationale"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'registry', description: 'Filter by check registry', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["registry"] || {}).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'description', description: 'Filter by check description', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["description"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'remediation', description: 'Filter by check remediation', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["remediation"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- { type: 'params', label: 'reason', description: 'Filter by check reason', operators: ['=', '!=',], values: (value) => { return Object.keys(distinctFields["reason"]).filter(item => item && item.toLowerCase().includes(value.toLowerCase())) } },
- ]
+ /**
+ * 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 defaultSuggestions = [
+ {
+ type: 'params',
+ label: 'condition',
+ description: 'Filter by check condition',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'condition'),
+ },
+ {
+ type: 'params',
+ label: 'file',
+ description: 'Filter by check file',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'file'),
+ },
+ {
+ type: 'params',
+ label: 'title',
+ description: 'Filter by check title',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'title'),
+ },
+ {
+ type: 'params',
+ label: 'result',
+ description: 'Filter by check result',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'result'),
+ },
+ {
+ type: 'params',
+ label: 'status',
+ description: 'Filter by check status',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'status'),
+ },
+ {
+ type: 'params',
+ label: 'rationale',
+ description: 'Filter by check rationale',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'rationale'),
+ },
+ {
+ type: 'params',
+ label: 'registry',
+ description: 'Filter by check registry',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'registry'),
+ },
+ {
+ type: 'params',
+ label: 'description',
+ description: 'Filter by check description',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'description'),
+ },
+ {
+ type: 'params',
+ label: 'remediation',
+ description: 'Filter by check remediation',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'remediation'),
+ },
+ {
+ type: 'params',
+ label: 'reason',
+ description: 'Filter by check reason',
+ operators: ['=', '!='],
+ values: (value) => getSuggestionsValues(value, 'reason'),
+ },
+ ];
+
+ const filteresSuggestions = defaultSuggestions.filter((item) =>
+ Object.keys(distinctFields).includes(item.label)
+ );
+ return filteresSuggestions;
+ };
+ this.suggestions[policy] = getSuggestionsFields();
}
async initialize() {
try {
this._isMount && this.setState({ loading: true });
this.lookingPolicy = false;
- const {data: {data: {affected_items: policies}}} = await WzRequest.apiReq(
- 'GET',
- `/sca/${this.props.agent.id}`,
- {}
- );
+ const {
+ data: {
+ data: { affected_items: policies },
+ },
+ } = await WzRequest.apiReq('GET', `/sca/${this.props.agent.id}`, {});
this._isMount && this.setState({ loading: false, policies });
} catch (error) {
- this.setState({ loading: false, policies: []});
+ this.setState({ loading: false, policies: [] });
const options: UIErrorLog = {
context: `${Inventory.name}.initialize`,
@@ -342,17 +441,24 @@ export class Inventory extends Component {
}
}
- filterPolicyChecks = () => !!this.state.items && this.state.items.filter(check =>
- this.state.filters.every(filter =>
+ 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())
- )
+ ? 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 => {
+ toggleDetails = (item) => {
const itemIdToExpandedRowMap = { ...this.state.itemIdToExpandedRowMap };
if (itemIdToExpandedRowMap[item.id]) {
@@ -361,30 +467,31 @@ export class Inventory extends Component {
let checks = '';
checks += (item.rules || []).length > 1 ? 'Checks' : 'Check';
checks += item.condition ? ` (Condition: ${item.condition})` : '';
- const complianceText = item.compliance && item.compliance.length
- ? item.compliance.map(el => `${el.key}: ${el.value}`).join('\n')
- : '';
- const rulesText = item.rules.length ? item.rules.map(el => el.rule).join('\n') : '';
+ const complianceText =
+ item.compliance && item.compliance.length
+ ? item.compliance.map((el) => `${el.key}: ${el.value}`).join('\n')
+ : '';
+ const rulesText = item.rules.length ? item.rules.map((el) => el.rule).join('\n') : '';
const listItems = [
{
title: 'Check not applicable due to:',
- description: item.reason
+ description: item.reason,
},
{
title: 'Rationale',
- description: item.rationale || '-'
+ description: item.rationale || '-',
},
{
title: 'Remediation',
- description: item.remediation || '-'
+ description: item.remediation || '-',
},
{
title: 'Description',
- description: item.description || '-'
+ description: item.description || '-',
},
{
title: (item.directory || '').includes(',') ? 'Paths' : 'Path',
- description: item.directory
+ description: item.directory,
},
{
title: checks,
@@ -392,15 +499,13 @@ export class Inventory extends Component {
},
{
title: 'Compliance',
- description:
- }
+ description: ,
+ },
];
- const itemsToShow = listItems.filter(x => {
+ const itemsToShow = listItems.filter((x) => {
return x.description;
});
- itemIdToExpandedRowMap[item.id] = (
-
- );
+ itemIdToExpandedRowMap[item.id] = ;
}
this.setState({ itemIdToExpandedRowMap });
};
@@ -436,11 +541,11 @@ export class Inventory extends Component {
}
buttonStat(text, field, value) {
- return
+ return ;
}
- onChangeTableChecks({ page: {index: pageIndex, size: pageSize} }){
- this.setState({ pageTableChecks: {pageIndex, pageSize} });
+ onChangeTableChecks({ page: { index: pageIndex, size: pageSize } }) {
+ this.setState({ pageTableChecks: { pageIndex, pageSize } });
}
render() {
@@ -448,34 +553,34 @@ export class Inventory extends Component {
return {
'data-test-subj': `sca-row-${idx}`,
className: 'customRowClass',
- onClick: () => this.loadScaPolicy(item)
+ onClick: () => this.loadScaPolicy(item),
};
};
const getChecksRowProps = (item, idx) => {
return {
'data-test-subj': `sca-check-row-${idx}`,
className: 'customRowClass',
- onClick: () => this.toggleDetails(item)
+ onClick: () => this.toggleDetails(item),
};
};
const sorting = {
sort: {
field: 'id',
- direction: 'asc'
- }
+ direction: 'asc',
+ },
};
const buttonPopover = (
this.setState({ showMoreInfo: !this.state.showMoreInfo })}>
-
+ onClick={() => this.setState({ showMoreInfo: !this.state.showMoreInfo })}
+ >
);
return (
- {(this.state.loading &&
+ {this.state.loading && (
@@ -483,162 +588,226 @@ export class Inventory extends Component {
)}
- {((this.props.agent && (this.props.agent || {}).status !== API_NAME_AGENT_STATUS.NEVER_CONNECTED && !this.state.policies.length && !this.state.loading) &&
-
- this.initialize()}>
- Refresh
-
-
- )}
+ {this.props.agent &&
+ (this.props.agent || {}).status !== API_NAME_AGENT_STATUS.NEVER_CONNECTED &&
+ !this.state.policies.length &&
+ !this.state.loading && (
+
+ this.initialize()}>
+ Refresh
+
+
+ )}
- {((this.props.agent && (this.props.agent || {}).status === API_NAME_AGENT_STATUS.NEVER_CONNECTED && !this.state.loading) &&
-
- this.initialize()}>
- Refresh
-
-
- )}
- {((this.props.agent && (this.props.agent || {}).os && !this.state.lookingPolicy && this.state.policies.length > 0 && !this.state.loading) &&
-
- {this.state.policies.length &&
-
- {this.state.policies.map((policy, idx) => (
-
-
-
-
-
-
- ))}
-
- }
-
-
-
-
-
-
-
-
-
- )}
- {((this.props.agent && (this.props.agent || {}).os && this.state.lookingPolicy && !this.state.loading) &&
-
-
-
-
- this.loadScaPolicy(false)}
- iconType="arrowLeft"
- aria-label="Back to policies"
- {...{ iconSize: 'l' }}
- />
-
-
-
- {this.state.lookingPolicy.name}
-
- this.setState({ showMoreInfo: false })}>
-
-
-
- Policy description: {this.state.lookingPolicy.description}
-
- Policy checksum: {this.state.lookingPolicy.hash_file}
-
-
-
-
-
-
-
-
- await this.downloadCsv()} >
- Export formatted
-
-
-
- this.loadScaPolicy(this.state.lookingPolicy)}>
- Refresh
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {this.props.agent &&
+ (this.props.agent || {}).status === API_NAME_AGENT_STATUS.NEVER_CONNECTED &&
+ !this.state.loading && (
+
+ this.initialize()}>
+ Refresh
+
+
+ )}
+ {this.props.agent &&
+ (this.props.agent || {}).os &&
+ !this.state.lookingPolicy &&
+ this.state.policies.length > 0 &&
+ !this.state.loading && (
+
+ {this.state.policies.length && (
+
+ {this.state.policies.map((policy, idx) => (
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+
+
+
+
+
+ )}
+ {this.props.agent &&
+ (this.props.agent || {}).os &&
+ this.state.lookingPolicy &&
+ !this.state.loading && (
+
+
+
+
+ this.loadScaPolicy(false)}
+ iconType="arrowLeft"
+ aria-label="Back to policies"
+ {...{ iconSize: 'l' }}
+ />
+
+
+
+
+ {this.state.lookingPolicy.name}
+
+ this.setState({ showMoreInfo: false })}
+ >
+
+
+
+ Policy description: {this.state.lookingPolicy.description}
+
+ Policy checksum: {this.state.lookingPolicy.hash_file}
+
+
+
+
+
+
+
+
+ await this.downloadCsv()}
+ >
+ Export formatted
+
+
+
+ this.loadScaPolicy(this.state.lookingPolicy)}
+ >
+ Refresh
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
- { this.setState({ filters }) }} />
-
-
+
+
+ {
+ this.setState({ filters });
+ }}
+ />
+
+
-
-
- this.onChangeTableChecks(change)}
- />
-
-
-
-
- )}
+
+
+ this.onChangeTableChecks(change)}
+ />
+
+
+
+
+ )}
);
diff --git a/public/components/wz-search-bar/lib/suggest-handler.ts b/public/components/wz-search-bar/lib/suggest-handler.ts
index d4e9251a88..f70f2d6fce 100644
--- a/public/components/wz-search-bar/lib/suggest-handler.ts
+++ b/public/components/wz-search-bar/lib/suggest-handler.ts
@@ -47,7 +47,7 @@ export class SuggestHandler extends BaseHandler {
this.filters = props.filters;
this.inputStage = 'field';
this.setInputValue = setInputValue;
- this.suggestItems = props.suggestions;
+ this.suggestItems = props.suggestions || [];
this.searchType = 'search';
this.lastCall = 0;
if (inputRef) this.inputRef = inputRef;