RED-9201 - UI for Component Mapping Tables

This commit is contained in:
Valentin Mihai 2024-06-05 00:09:32 +03:00
parent d3f293f622
commit a960b837df
12 changed files with 308 additions and 9 deletions

View File

@ -0,0 +1,66 @@
<section class="dialog">
<div
[innerHTML]="'add-edit-component-mapping.dialog.title' | translate: { type: data.mapping ? 'edit' : 'add' }"
class="dialog-header heading-l"
></div>
<form (submit)="save()" [formGroup]="form">
<div class="dialog-content">
<div class="row">
<div class="iqser-input-group required w-300">
<label translate="add-edit-component-mapping.form.name"></label>
<input
[placeholder]="'add-edit-component-mapping.form.name-placeholder' | translate"
formControlName="name"
name="label"
type="text"
/>
</div>
<div class="iqser-input-group w-100 version" *ngIf="data?.mapping?.version">
<label translate="add-edit-component-mapping.form.version"></label>
<span> {{ data.mapping.version }} </span>
<!-- <input [placeholder]="'add-edit-component-mapping.form.name-placeholder' | translate" formControlName="name" name="label" type="text" />-->
</div>
</div>
<div class="iqser-input-group required">
<label translate="add-edit-component-mapping.form.file"></label>
<iqser-upload-file (fileChanged)="fileChanged($event)" />
</div>
<div class="row">
<div class="iqser-input-group required w-150">
<label translate="add-edit-component-mapping.form.delimiter"></label>
<input
[placeholder]="'add-edit-component-mapping.form.delimiter-placeholder' | translate"
formControlName="delimiter"
name="delimiter"
type="text"
/>
</div>
<div class="iqser-input-group required w-150">
<label translate="add-edit-component-mapping.form.encoding-type"></label>
<mat-form-field>
<mat-select formControlName="encodingType">
<mat-option *ngFor="let type of encodingTypeOptions" [value]="type">
{{ translations[type] | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<div class="dialog-actions">
<iqser-icon-button
(action)="save()"
[disabled]="disabled"
[label]="'add-edit-component-mapping.actions.save' | translate"
[type]="iconButtonTypes.primary"
></iqser-icon-button>
</div>
</form>
<iqser-circle-button class="dialog-close" icon="iqser:close" mat-dialog-close></iqser-circle-button>
</section>

View File

@ -0,0 +1,21 @@
.row {
display: flex;
margin-top: 14px;
> *:not(:last-child) {
margin-right: 16px;
}
.iqser-input-group {
margin-top: 0;
}
.version {
margin-left: 50px;
span {
margin-top: 10px;
font-size: 15px;
}
}
}

View File

@ -0,0 +1,81 @@
import { Component } from '@angular/core';
import { CircleButtonComponent, IconButtonComponent, IconButtonTypes, IqserDialogComponent, IqserUploadFileModule } from '@iqser/common-ui';
import { FileAttributeEncodingTypes, IComponentMapping } from '@red/domain';
import { FormBuilder, ReactiveFormsModule, UntypedFormGroup, Validators } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { NgForOf, NgIf } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatDialogClose } from '@angular/material/dialog';
import { MatOption } from '@angular/material/autocomplete';
import { MatSelect } from '@angular/material/select';
import { fileAttributeEncodingTypesTranslations } from '@translations/file-attribute-encoding-types-translations';
interface DialogData {
mapping: IComponentMapping;
}
interface DialogResult {}
@Component({
templateUrl: './add-edit-component-mapping-dialog.component.html',
styleUrls: ['./add-edit-component-mapping-dialog.component.scss'],
standalone: true,
imports: [
TranslateModule,
ReactiveFormsModule,
NgIf,
MatFormFieldModule,
NgForOf,
CircleButtonComponent,
MatDialogClose,
IqserUploadFileModule,
MatOption,
MatSelect,
IconButtonComponent,
],
})
export class AddEditComponentMappingDialogComponent extends IqserDialogComponent<
AddEditComponentMappingDialogComponent,
DialogData,
DialogResult
> {
protected readonly encodingTypeOptions = Object.keys(FileAttributeEncodingTypes);
protected readonly translations = fileAttributeEncodingTypesTranslations;
protected readonly iconButtonTypes = IconButtonTypes;
form!: UntypedFormGroup;
constructor(private readonly _formBuilder: FormBuilder) {
super();
this.form = this.#getForm();
}
get file() {
return this.form.get('file').value;
}
fileChanged(file: Blob | null) {
if (file) {
const fileReader = new FileReader();
fileReader.onload = () => {
const binaryContent = <string>fileReader.result;
this.form.get('file').setValue(binaryContent);
};
fileReader.readAsBinaryString(file as Blob);
} else {
this.form.controls['file'].setValue('');
}
}
save() {
this.dialogRef.close({ ...this.data.mapping, ...this.form.getRawValue() });
}
#getForm(): UntypedFormGroup {
return this._formBuilder.group({
name: [this.data?.mapping?.name, Validators.required],
file: [this.data?.mapping?.file, Validators.required],
delimiter: [this.data?.mapping?.delimiter ?? ',', Validators.required],
encodingType: this.encodingTypeOptions.find(e => e === this.data?.mapping?.encodingType) ?? this.encodingTypeOptions[0],
});
}
}

View File

@ -1,14 +1,23 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ListingComponent, TableColumnConfig, listingProvidersFactory, LoadingService, IconButtonTypes } from '@iqser/common-ui'; import {
ListingComponent,
TableColumnConfig,
listingProvidersFactory,
LoadingService,
IconButtonTypes,
IqserDialog,
} from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { defaultColorsTranslations } from '@translations/default-colors-translations'; import { defaultColorsTranslations } from '@translations/default-colors-translations';
import { Roles } from '@users/roles'; import { Roles } from '@users/roles';
import { getCurrentUser } from '@common-ui/users'; import { getCurrentUser } from '@common-ui/users';
import { User } from '@red/domain'; import { User } from '@red/domain';
import { ComponentMapping } from '@red/domain'; import { ComponentMapping } from '@red/domain';
import { combineLatest } from 'rxjs'; import { combineLatest, firstValueFrom } from 'rxjs';
import { ComponentMappingsService } from '@services/entity-services/component-mappings.service'; import { ComponentMappingsService } from '@services/entity-services/component-mappings.service';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { AddEditComponentMappingDialogComponent } from './add-edit-component-mapping-dialog/add-edit-component-mapping-dialog.component';
import { AdminDialogService } from '../../services/admin-dialog.service';
@Component({ @Component({
templateUrl: './component-mappings-screen.component.html', templateUrl: './component-mappings-screen.component.html',
@ -30,6 +39,8 @@ export class ComponentMappingsScreenComponent extends ListingComponent<Component
constructor( constructor(
private readonly _loadingService: LoadingService, private readonly _loadingService: LoadingService,
private readonly _componentMappingService: ComponentMappingsService, private readonly _componentMappingService: ComponentMappingsService,
private readonly _iqserDialog: IqserDialog,
private readonly _dialogService: AdminDialogService,
) { ) {
super(); super();
this.context$ = combineLatest([this._componentMappingService.loadData()]).pipe( this.context$ = combineLatest([this._componentMappingService.loadData()]).pipe(
@ -41,7 +52,22 @@ export class ComponentMappingsScreenComponent extends ListingComponent<Component
this._loadingService.stop(); this._loadingService.stop();
} }
openAddEditComponentMappingDialog(entity?: ComponentMapping) {} async openAddEditComponentMappingDialog(mapping?: ComponentMapping) {
const dialog = this._iqserDialog.openDefault(AddEditComponentMappingDialogComponent, {
data: {
mapping,
},
});
const result = await dialog.result();
if (result) {
this._componentMappingService.saveData(result);
}
}
openDeleteComponentMappingDialog(entity?: ComponentMapping) {} openDeleteComponentMappingDialog(entity?: ComponentMapping) {
this._dialogService.openDialog('confirm', null, async () => {
// this._loadingService.start();
// this._loadingService.stop();
});
}
} }

View File

@ -7,36 +7,54 @@ const DATA = [
{ {
id: '1', id: '1',
name: 'OECD Number', name: 'OECD Number',
file: 'some file name',
delimiter: ',',
encodingType: 'UTF-8',
version: 2, version: 2,
searchKey: 'OECD Number', searchKey: 'OECD Number',
}, },
{ {
id: '2', id: '2',
name: 'Study Title', name: 'Study Title',
file: 'some file name',
delimiter: ';',
encodingType: 'ASCII',
version: 1, version: 1,
searchKey: 'Study Title', searchKey: 'Study Title',
}, },
{ {
id: '3', id: '3',
name: 'Report Number', name: 'Report Number',
file: 'some file name',
delimiter: '.',
encodingType: 'ISO',
version: 2, version: 2,
searchKey: 'Report Number', searchKey: 'Report Number',
}, },
{ {
id: '4', id: '4',
name: 'GLP Study', name: 'GLP Study',
file: 'some file name',
delimiter: '"',
encodingType: 'UTF-8',
version: 5, version: 5,
searchKey: 'GLP Study', searchKey: 'GLP Study',
}, },
{ {
id: '5', id: '5',
name: 'Performing Laboratory', name: 'Performing Laboratory',
file: 'some file name',
delimiter: ']',
encodingType: 'UTF-8',
version: 2, version: 2,
searchKey: 'Performing Laboratory', searchKey: 'Performing Laboratory',
}, },
{ {
id: '6', id: '6',
name: 'Test', name: 'Test',
file: 'some file name',
delimiter: ';',
encodingType: 'UTF-8',
version: 3, version: 3,
searchKey: 'Test', searchKey: 'Test',
}, },
@ -49,4 +67,14 @@ export class ComponentMappingsService extends EntitiesService<IComponentMapping,
loadData(): Observable<ComponentMapping[]> { loadData(): Observable<ComponentMapping[]> {
return of(DATA); return of(DATA);
} }
saveData(mapping: any): Observable<ComponentMapping> {
if (!mapping.id) {
mapping.id = (Number(DATA[DATA.length - 1].id) + 1).toString();
mapping.version = 1;
mapping.searchKey = mapping.name;
}
DATA.push(mapping);
return of(mapping);
}
} }

View File

@ -1,9 +1,9 @@
{ {
"ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null, "ADMIN_CONTACT_URL": null,
"API_URL": "https://dan.iqser.cloud", "API_URL": "https://frontend2.iqser.cloud",
"APP_NAME": "RedactManager", "APP_NAME": "RedactManager",
"IS_DOCUMINE": false, "IS_DOCUMINE": true,
"RULE_EDITOR_DEV_ONLY": false, "RULE_EDITOR_DEV_ONLY": false,
"AUTO_READ_TIME": 3, "AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40", "BACKEND_APP_VERSION": "4.4.40",
@ -13,13 +13,13 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3, "MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction", "OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null, "OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://dan.iqser.cloud/auth", "OAUTH_URL": "https://frontend2.iqser.cloud/auth",
"RECENT_PERIOD_IN_HOURS": 24, "RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural", "SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
"ANNOTATIONS_THRESHOLD": 1000, "ANNOTATIONS_THRESHOLD": 1000,
"THEME": "redact", "THEME": "scm",
"BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/redact/", "BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/scm/",
"AVAILABLE_NOTIFICATIONS_DAYS": 30, "AVAILABLE_NOTIFICATIONS_DAYS": 30,
"AVAILABLE_OLD_NOTIFICATIONS_MINUTES": 60, "AVAILABLE_OLD_NOTIFICATIONS_MINUTES": 60,
"NOTIFICATIONS_THRESHOLD": 1000, "NOTIFICATIONS_THRESHOLD": 1000,

View File

@ -94,6 +94,23 @@
}, },
"save": "Dossier-Vorlage speichern" "save": "Dossier-Vorlage speichern"
}, },
"add-edit-component-mapping": {
"actions": {
"save": ""
},
"dialog": {
"title": ""
},
"form": {
"delimiter": "",
"delimiter-placeholder": "",
"encoding-type": "",
"file": "",
"name": "",
"name-placeholder": "",
"version": ""
}
},
"add-edit-dossier-attribute": { "add-edit-dossier-attribute": {
"error": { "error": {
"generic": "Attribut konnte nicht gespeichert werden!" "generic": "Attribut konnte nicht gespeichert werden!"

View File

@ -94,6 +94,23 @@
}, },
"save": "Save dossier template" "save": "Save dossier template"
}, },
"add-edit-component-mapping": {
"actions": {
"save": "Save mapping"
},
"dialog": {
"title": "{type, select, add{Add New} edit{Edit} other{}} Component Mapping"
},
"form": {
"delimiter": "",
"delimiter-placeholder": "",
"encoding-type": "",
"file": "Mapping file",
"name": "Mapping name",
"name-placeholder": "Mapping name",
"version": "Version"
}
},
"add-edit-dossier-attribute": { "add-edit-dossier-attribute": {
"error": { "error": {
"generic": "Failed to save attribute" "generic": "Failed to save attribute"

View File

@ -94,6 +94,23 @@
}, },
"save": "Dossier-Vorlage speichern" "save": "Dossier-Vorlage speichern"
}, },
"add-edit-component-mapping": {
"actions": {
"save": ""
},
"dialog": {
"title": ""
},
"form": {
"delimiter": "",
"delimiter-placeholder": "",
"encoding-type": "",
"file": "",
"name": "",
"name-placeholder": "",
"version": ""
}
},
"add-edit-dossier-attribute": { "add-edit-dossier-attribute": {
"error": { "error": {
"generic": "Attribut konnte nicht gespeichert werden!" "generic": "Attribut konnte nicht gespeichert werden!"

View File

@ -94,6 +94,23 @@
}, },
"save": "Save dossier template" "save": "Save dossier template"
}, },
"add-edit-component-mapping": {
"actions": {
"save": "Save mapping"
},
"dialog": {
"title": "{type, select, add{Add New} edit{Edit} other{}} Component Mapping"
},
"form": {
"delimiter": "Delimiter",
"delimiter-placeholder": "Delimiter",
"encoding-type": "Encoding type",
"file": "Mapping file",
"name": "Mapping name",
"name-placeholder": "Mapping name",
"version": "Version"
}
},
"add-edit-dossier-attribute": { "add-edit-dossier-attribute": {
"error": { "error": {
"generic": "Failed to save attribute!" "generic": "Failed to save attribute!"

View File

@ -4,11 +4,17 @@ import { IListable } from '@iqser/common-ui';
export class ComponentMapping implements IComponentMapping, IListable { export class ComponentMapping implements IComponentMapping, IListable {
readonly id: string; readonly id: string;
readonly name: string; readonly name: string;
readonly file: string;
readonly delimiter: string;
readonly encodingType: string;
readonly version: number; readonly version: number;
constructor(componentMapping: IComponentMapping) { constructor(componentMapping: IComponentMapping) {
this.id = componentMapping.id; this.id = componentMapping.id;
this.name = componentMapping.name; this.name = componentMapping.name;
this.file = componentMapping.file;
this.delimiter = componentMapping.delimiter;
this.encodingType = componentMapping.encodingType;
this.version = componentMapping.version; this.version = componentMapping.version;
} }

View File

@ -1,5 +1,8 @@
export interface IComponentMapping { export interface IComponentMapping {
id: string; id: string;
name: string; name: string;
file: string;
version: number; version: number;
delimiter: string;
encodingType: string;
} }