diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html index e8951ad45..6aae70c94 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.html @@ -14,11 +14,18 @@
{{ 'file-attributes-csv-import.key-column' | translate }} - - + + + {{ field }} - +
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss index 8b3df0e3a..447df33f7 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.scss @@ -235,7 +235,7 @@ height: calc(100% - 80px); ::ng-deep.cdk-virtual-scroll-content-wrapper { - grid-template-columns: 30px minmax(0, 20vw) 150px auto auto auto 11px; + grid-template-columns: 30px minmax(0, 25vw) 150px auto auto auto 11px; .table-item { > div { @@ -277,7 +277,7 @@ &.has-scrollbar:hover { ::ng-deep.cdk-virtual-scroll-content-wrapper { - grid-template-columns: 30px minmax(0, 20vw) 150px auto auto auto; + grid-template-columns: 30px minmax(0, 25vw) 150px auto auto auto; } } } diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts index ae71e6f5e..60f282035 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component.ts @@ -1,11 +1,13 @@ -import { Component, Inject, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Component, Inject, ViewChild } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { AppStateService } from '../../../../state/app-state.service'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import * as Papa from 'papaparse'; import { FileAttributesControllerService } from '@redaction/red-ui-http'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { debounce } from '../../../../utils/debounce'; +import { Observable } from 'rxjs'; +import { map, startWith } from 'rxjs/operators'; enum FieldType { Text = 'Text', @@ -28,7 +30,7 @@ interface Field { templateUrl: './file-attributes-csv-import-dialog.component.html', styleUrls: ['./file-attributes-csv-import-dialog.component.scss'] }) -export class FileAttributesCsvImportDialogComponent implements OnInit { +export class FileAttributesCsvImportDialogComponent { public csvFile: File; public ruleSetId: string; public parseResult: { data: any[]; errors: any[]; meta: any; fields: Field[] }; @@ -40,6 +42,7 @@ export class FileAttributesCsvImportDialogComponent implements OnInit { public searchForm: FormGroup; public filteredFields: Field[]; public previewExpanded = true; + public filteredKeyOptions: Observable; @ViewChild(CdkVirtualScrollViewport, { static: false }) cdkVirtualScrollViewport: CdkVirtualScrollViewport; @@ -58,7 +61,7 @@ export class FileAttributesCsvImportDialogComponent implements OnInit { }); this.baseConfigForm = this._formBuilder.group({ - filenameMappingColumnHeaderName: [undefined, Validators.required], + filenameMappingColumnHeaderName: ['', [Validators.required, this._autocompleteStringValidator()]], delimiter: [undefined, Validators.required], encoding: ['UTF-8', Validators.required] }); @@ -68,20 +71,20 @@ export class FileAttributesCsvImportDialogComponent implements OnInit { this.searchForm.valueChanges.subscribe((value) => this._executeSearch(value)); } - ngOnInit(): void { - setTimeout(() => { - // Calculate viewport size after dialog is completely expanded - if (this.cdkVirtualScrollViewport) { - this.cdkVirtualScrollViewport.checkViewportSize(); - } - }, 500); - } - @debounce(200) private _executeSearch(value: { query: string }) { this.filteredFields = this.parseResult.fields.filter((f) => f.csvColumn.toLowerCase().includes(value.query.toLowerCase())); } + private _autocompleteStringValidator(): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } | null => { + if ((this.parseResult?.meta?.fields || []).indexOf(control.value) !== -1) { + return null; /* valid option selected */ + } + return { invalidAutocompleteString: { value: control.value } }; + }; + } + private _readFile() { const reader = new FileReader(); reader.addEventListener('load', async (event) => { @@ -95,6 +98,11 @@ export class FileAttributesCsvImportDialogComponent implements OnInit { } this.parseResult.fields = this.parseResult.meta.fields.map((field) => this._buildAttribute(field)); this.filteredFields = [...this.parseResult.fields]; + + this.filteredKeyOptions = this.baseConfigForm.get('filenameMappingColumnHeaderName').valueChanges.pipe( + startWith(''), + map((value: string) => this.parseResult.meta.fields.filter((field) => field.toLowerCase().indexOf(value.toLowerCase()) !== -1)) + ); }); reader.readAsText(this.csvFile, this.baseConfigForm.get('encoding').value); } diff --git a/apps/red-ui/src/app/modules/mat-config/mat-config.module.ts b/apps/red-ui/src/app/modules/mat-config/mat-config.module.ts index 79e2e3042..1ef613d30 100644 --- a/apps/red-ui/src/app/modules/mat-config/mat-config.module.ts +++ b/apps/red-ui/src/app/modules/mat-config/mat-config.module.ts @@ -15,6 +15,7 @@ import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatAutocompleteModule } from '@angular/material/autocomplete'; const matImports = [ MatDialogModule, @@ -32,7 +33,8 @@ const matImports = [ MatDatepickerModule, MatInputModule, MatSelectModule, - MatProgressBarModule + MatProgressBarModule, + MatAutocompleteModule ]; @NgModule({ diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index b38d12861..36e4b62af 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -1154,7 +1154,7 @@ "encoding": "Encoding", "encoding-placeholder": "UTF-8", "key-column": "Key Column", - "key-column-placeholder": "Select Column ...", + "key-column-placeholder": "Select column...", "total-rows": "{{rows}} rows in total", "available": "{{value}} available", "selected": "{{value}} selected", diff --git a/apps/red-ui/src/assets/styles/red-autocomplete.scss b/apps/red-ui/src/assets/styles/red-autocomplete.scss new file mode 100644 index 000000000..cd517e71b --- /dev/null +++ b/apps/red-ui/src/assets/styles/red-autocomplete.scss @@ -0,0 +1,10 @@ +@import 'red-variables'; +@import 'red-mixins'; + +.mat-autocomplete-panel { + @include scroll-bar; + + .mat-option { + font-size: inherit; + } +} diff --git a/apps/red-ui/src/assets/styles/red-theme.scss b/apps/red-ui/src/assets/styles/red-theme.scss index 46008285d..8802af2d4 100644 --- a/apps/red-ui/src/assets/styles/red-theme.scss +++ b/apps/red-ui/src/assets/styles/red-theme.scss @@ -8,6 +8,7 @@ @import 'red-input'; @import 'red-button'; @import 'red-select'; +@import 'red-autocomplete'; @import 'red-list'; @import 'red-checkbox'; @import 'red-toggle';