From 3a3743a437b43006e250af63c9cf1f9a3b172dec Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 10 Jan 2023 16:14:08 -0800 Subject: [PATCH] Improved field mapping UX (#330) (#337) * fixed issues; improved UX Signed-off-by: Amardeepsingh Siglani * removed unwanted change Signed-off-by: Amardeepsingh Siglani * override default mapping with created Signed-off-by: Amardeepsingh Siglani Signed-off-by: Amardeepsingh Siglani (cherry picked from commit d0e184d691cf12a9405684088e5779a3040da053) Co-authored-by: Amardeepsingh Siglani Signed-off-by: AWSHurneyt --- .../FieldMappingsTable.tsx | 25 +++++- .../containers/ConfigureFieldMapping.tsx | 88 ++++++++++++------- 2 files changed, 76 insertions(+), 37 deletions(-) diff --git a/public/pages/CreateDetector/components/ConfigureFieldMapping/components/RequiredFieldMapping/FieldMappingsTable.tsx b/public/pages/CreateDetector/components/ConfigureFieldMapping/components/RequiredFieldMapping/FieldMappingsTable.tsx index 9c445c5d7..1a255ffbd 100644 --- a/public/pages/CreateDetector/components/ConfigureFieldMapping/components/RequiredFieldMapping/FieldMappingsTable.tsx +++ b/public/pages/CreateDetector/components/ConfigureFieldMapping/components/RequiredFieldMapping/FieldMappingsTable.tsx @@ -6,6 +6,7 @@ import React, { Component } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { + CriteriaWithPagination, EuiBasicTableColumn, EuiEmptyPrompt, EuiIcon, @@ -42,12 +43,27 @@ interface FieldMappingsTableProps extends RouteCompon mappingProps: MappingProps[T]; } -interface FieldMappingsTableState {} +interface FieldMappingsTableState { + pageIndex: number; +} export default class FieldMappingsTable extends Component< FieldMappingsTableProps, FieldMappingsTableState > { + constructor(props: FieldMappingsTableProps) { + super(props); + this.state = { + pageIndex: 0, + }; + } + + private onTableChange = (nextValues: CriteriaWithPagination) => { + this.setState({ + pageIndex: nextValues.page.index, + }); + }; + render() { const { loading, indexFields, ruleFields } = this.props; let items: FieldMappingsTableItem[]; @@ -70,7 +86,6 @@ export default class FieldMappingsTable extends Compo { field: 'ruleFieldName', name: 'Rule field name', - sortable: true, dataType: 'string', width: '25%', render: (ruleFieldName: string) => ruleFieldName || DEFAULT_EMPTY_DATA, @@ -85,7 +100,6 @@ export default class FieldMappingsTable extends Compo { field: 'logFieldName', name: 'Log field name', - sortable: true, dataType: 'string', width: '45%', render: (logFieldName: string, entry: FieldMappingsTableItem) => { @@ -150,9 +164,12 @@ export default class FieldMappingsTable extends Compo loading={loading} items={items} columns={columns} - pagination={true} + pagination={{ + pageIndex: this.state.pageIndex, + }} sorting={sorting} isSelectable={false} + onTableChange={this.onTableChange} message={ { - existingMappings[ruleFieldName] = mappingsView.response.properties[ruleFieldName].path; + existingMappings[ruleFieldName] = + this.state.createdMappings[ruleFieldName] || + mappingsView.response.properties[ruleFieldName].path; }); this.setState({ createdMappings: existingMappings, - mappingsData: { - ...mappingsView.response, - unmapped_field_aliases: [ - 'timestamp', - ...(mappingsView.response.unmapped_field_aliases || []), - ], - }, + mappingsData: mappingsView.response, }); this.updateMappingSharedState(existingMappings); } @@ -111,11 +107,16 @@ export default class ConfigureFieldMapping extends Component< return invalidFields; } - onMappingCreation = (ruleFieldName: string, indxFieldName: string): void => { + onMappingCreation = (ruleFieldName: string, indexFieldName: string): void => { const newMappings: ruleFieldToIndexFieldMap = { ...this.state.createdMappings, - [ruleFieldName]: indxFieldName, + [ruleFieldName]: indexFieldName, }; + + if (!indexFieldName) { + delete newMappings[ruleFieldName]; + } + const invalidMappingFieldNames = this.getInvalidMappingFieldNames(newMappings); this.setState({ createdMappings: newMappings, @@ -142,17 +143,28 @@ export default class ConfigureFieldMapping extends Component< ...createdMappings, }; - // read only data const mappedRuleFields: string[] = []; - const mappedLogFields: string[] = []; + const logFields: Set = new Set(mappingsData.unmapped_index_fields || []); + let pendingCount = mappingsData.unmapped_field_aliases?.length || 0; + const unmappedRuleFields = [...(mappingsData.unmapped_field_aliases || [])]; + Object.keys(mappingsData.properties).forEach((ruleFieldName) => { mappedRuleFields.unshift(ruleFieldName); - mappedLogFields.unshift(mappingsData.properties[ruleFieldName].path); + + // Need this check to avoid adding undefined value + // When user removes existing mapping for default mapped values, the mapping will be undefined + if (existingMappings[ruleFieldName]) { + logFields.add(existingMappings[ruleFieldName]); + } }); - // edit data - const ruleFields = [...(mappingsData.unmapped_field_aliases || [])]; - const indexFields = [...(mappingsData.unmapped_index_fields || [])]; + Object.keys(existingMappings).forEach((mappedRuleField) => { + if (unmappedRuleFields.includes(mappedRuleField)) { + pendingCount--; + } + }); + + const indexFieldOptions = Array.from(logFields); return (
@@ -168,24 +180,31 @@ export default class ConfigureFieldMapping extends Component< - {ruleFields.length > 0 ? ( + {unmappedRuleFields.length > 0 ? ( <> - -

- To generate accurate findings, we recommend mapping the following security rules - fields with the log field from your data source. -

-
+ {pendingCount > 0 ? ( + +

+ To generate accurate findings, we recommend mapping the following security rules + fields with the log fields in your data source. +

+
+ ) : ( + +

Your data source have been mapped with all security rule fields.

+
+ )} + - + {...this.props} loading={loading} - ruleFields={ruleFields} - indexFields={indexFields} + ruleFields={unmappedRuleFields} + indexFields={indexFieldOptions} mappingProps={{ type: MappingViewType.Edit, existingMappings, @@ -213,7 +232,7 @@ export default class ConfigureFieldMapping extends Component< buttonContent={
-

{`View mapped fields (${mappedRuleFields.length})`}

+

{`Default mapped fields (${mappedRuleFields.length})`}

} @@ -222,13 +241,16 @@ export default class ConfigureFieldMapping extends Component< initialIsOpen={false} > - + {...this.props} loading={loading} ruleFields={mappedRuleFields} - indexFields={mappedLogFields} + indexFields={indexFieldOptions} mappingProps={{ - type: MappingViewType.Readonly, + type: MappingViewType.Edit, + existingMappings, + invalidMappingFieldNames, + onMappingCreation: this.onMappingCreation, }} />