RED-9201 - added all mapping actions
This commit is contained in:
parent
40cc4a3d37
commit
13c1a2a0b0
@ -16,16 +16,15 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-100 version" *ngIf="data?.mapping?.version">
|
||||
<div class="iqser-input-group w-100 version" *ngIf="data?.mapping?.id">
|
||||
<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)" />
|
||||
<iqser-upload-file (fileChanged)="fileChanged($event)" [file]="activeFile" [accept]="'.csv'" />
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@ -42,7 +41,7 @@
|
||||
<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-select formControlName="encoding">
|
||||
<mat-option *ngFor="let type of encodingTypeOptions" [value]="type">
|
||||
{{ translations[type] | translate }}
|
||||
</mat-option>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } 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';
|
||||
@ -9,11 +9,20 @@ 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';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { ComponentMappingsService } from '@services/entity-services/component-mappings.service';
|
||||
|
||||
interface DialogData {
|
||||
dossierTemplateId: string;
|
||||
mapping: IComponentMapping;
|
||||
}
|
||||
interface DialogResult {}
|
||||
interface DialogResult {
|
||||
id: string;
|
||||
name: string;
|
||||
file: Blob;
|
||||
encoding: string;
|
||||
delimiter: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: './add-edit-component-mapping-dialog.component.html',
|
||||
@ -33,37 +42,38 @@ interface DialogResult {}
|
||||
IconButtonComponent,
|
||||
],
|
||||
})
|
||||
export class AddEditComponentMappingDialogComponent extends IqserDialogComponent<
|
||||
AddEditComponentMappingDialogComponent,
|
||||
DialogData,
|
||||
DialogResult
|
||||
> {
|
||||
export class AddEditComponentMappingDialogComponent
|
||||
extends IqserDialogComponent<AddEditComponentMappingDialogComponent, DialogData, DialogResult>
|
||||
implements OnInit
|
||||
{
|
||||
protected readonly encodingTypeOptions = Object.keys(FileAttributeEncodingTypes);
|
||||
protected readonly translations = fileAttributeEncodingTypesTranslations;
|
||||
protected readonly iconButtonTypes = IconButtonTypes;
|
||||
activeFile: File;
|
||||
form!: UntypedFormGroup;
|
||||
|
||||
constructor(private readonly _formBuilder: FormBuilder) {
|
||||
constructor(
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _componentMappingService: ComponentMappingsService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.form = this.#getForm();
|
||||
}
|
||||
|
||||
get file() {
|
||||
return this.form.get('file').value;
|
||||
async ngOnInit() {
|
||||
if (this.data.mapping?.fileName) {
|
||||
this.activeFile = { name: this.data.mapping.fileName } as File;
|
||||
const fileContent = await firstValueFrom(
|
||||
this._componentMappingService.getComponentMappingFile(this.data.dossierTemplateId, this.data.mapping.id),
|
||||
);
|
||||
const file = new Blob([fileContent], { type: 'text/csv' });
|
||||
this.form.get('file').setValue(file);
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
}
|
||||
|
||||
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('');
|
||||
}
|
||||
fileChanged(file: Blob) {
|
||||
this.form.get('file').setValue(file);
|
||||
}
|
||||
|
||||
save() {
|
||||
@ -73,9 +83,9 @@ export class AddEditComponentMappingDialogComponent extends IqserDialogComponent
|
||||
#getForm(): UntypedFormGroup {
|
||||
return this._formBuilder.group({
|
||||
name: [this.data?.mapping?.name, Validators.required],
|
||||
file: [this.data?.mapping?.file, Validators.required],
|
||||
file: [null, Validators.required],
|
||||
encoding: this.encodingTypeOptions.find(e => e === this.data?.mapping?.encoding) ?? this.encodingTypeOptions[0],
|
||||
delimiter: [this.data?.mapping?.delimiter ?? ',', Validators.required],
|
||||
encodingType: this.encodingTypeOptions.find(e => e === this.data?.mapping?.encodingType) ?? this.encodingTypeOptions[0],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,14 +20,7 @@
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container">
|
||||
<iqser-table
|
||||
[headerTemplate]="headerTemplate"
|
||||
[bulkActions]="bulkActions"
|
||||
[itemSize]="80"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
[selectionEnabled]="true"
|
||||
emptyColumnWidth="2fr"
|
||||
>
|
||||
<iqser-table [headerTemplate]="headerTemplate" [itemSize]="80" [tableColumnConfigs]="tableColumnConfigs" emptyColumnWidth="2fr">
|
||||
</iqser-table>
|
||||
</div>
|
||||
</div>
|
||||
@ -51,17 +44,6 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #bulkActions>
|
||||
<ng-container *allow="roles.componentMappings.write; if: currentUser.isAdmin">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteComponentMappingDialog()"
|
||||
*ngIf="listingService.areSomeSelected$ | async"
|
||||
[tooltip]="'component-mappings-screen.bulk-actions.delete' | translate"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #tableItemTemplate let-entity="entity">
|
||||
<div>
|
||||
<div class="label cell">
|
||||
@ -69,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<span>{{ entity.value }}</span>
|
||||
<span>{{ entity.version }}</span>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
|
||||
@ -11,13 +11,14 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { defaultColorsTranslations } from '@translations/default-colors-translations';
|
||||
import { Roles } from '@users/roles';
|
||||
import { getCurrentUser } from '@common-ui/users';
|
||||
import { User } from '@red/domain';
|
||||
import { DOSSIER_TEMPLATE_ID, User } from '@red/domain';
|
||||
import { ComponentMapping } from '@red/domain';
|
||||
import { combineLatest, firstValueFrom } from 'rxjs';
|
||||
import { ComponentMappingsService } from '@services/entity-services/component-mappings.service';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { map, 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';
|
||||
import { getParam } from '@common-ui/utils';
|
||||
|
||||
@Component({
|
||||
templateUrl: './component-mappings-screen.component.html',
|
||||
@ -27,14 +28,15 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
export class ComponentMappingsScreenComponent extends ListingComponent<ComponentMapping> implements OnInit {
|
||||
tableColumnConfigs: readonly TableColumnConfig<ComponentMapping>[] = [
|
||||
{ label: _('component-mappings-screen.table-col-names.name'), sortByKey: 'searchKey' },
|
||||
{ label: _('component-mappings-screen.table-col-names.version'), width: '2fr' },
|
||||
{ label: _('component-mappings-screen.table-col-names.version') },
|
||||
];
|
||||
readonly tableHeaderLabel = _('component-mappings-screen.table-header.title');
|
||||
readonly context$;
|
||||
protected readonly context$;
|
||||
protected readonly currentUser = getCurrentUser<User>();
|
||||
protected readonly translations = defaultColorsTranslations;
|
||||
protected readonly roles = Roles;
|
||||
protected readonly iconButtonTypes = IconButtonTypes;
|
||||
readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
|
||||
|
||||
constructor(
|
||||
private readonly _loadingService: LoadingService,
|
||||
@ -43,8 +45,13 @@ export class ComponentMappingsScreenComponent extends ListingComponent<Component
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
) {
|
||||
super();
|
||||
this.context$ = combineLatest([this._componentMappingService.loadData()]).pipe(
|
||||
tap(([mappings]) => this.entitiesService.setEntities(mappings)),
|
||||
this.context$ = this.loadData$();
|
||||
}
|
||||
|
||||
loadData$() {
|
||||
return combineLatest([this._componentMappingService.getComponentMappings(this.#dossierTemplateId)]).pipe(
|
||||
map(([mappingList]) => mappingList.componentMappingList),
|
||||
tap(mappings => this.entitiesService.setEntities(mappings)),
|
||||
);
|
||||
}
|
||||
|
||||
@ -55,19 +62,29 @@ export class ComponentMappingsScreenComponent extends ListingComponent<Component
|
||||
async openAddEditComponentMappingDialog(mapping?: ComponentMapping) {
|
||||
const dialog = this._iqserDialog.openDefault(AddEditComponentMappingDialogComponent, {
|
||||
data: {
|
||||
dossierTemplateId: this.#dossierTemplateId,
|
||||
mapping,
|
||||
},
|
||||
});
|
||||
const result = await dialog.result();
|
||||
if (result) {
|
||||
this._componentMappingService.saveData(result);
|
||||
this._loadingService.start();
|
||||
const { id, name, encoding, delimiter } = result;
|
||||
const newMapping = { id, name, encoding, delimiter };
|
||||
await firstValueFrom(this._componentMappingService.createComponentMapping(this.#dossierTemplateId, newMapping, result.file));
|
||||
await firstValueFrom(this.loadData$());
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
openDeleteComponentMappingDialog(entity?: ComponentMapping) {
|
||||
this._dialogService.openDialog('confirm', null, async () => {
|
||||
// this._loadingService.start();
|
||||
// this._loadingService.stop();
|
||||
openDeleteComponentMappingDialog(entity: ComponentMapping) {
|
||||
this._dialogService.openDialog('confirm', null, async confirmation => {
|
||||
if (confirmation) {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(this._componentMappingService.deleteComponentMapping(this.#dossierTemplateId, entity.id));
|
||||
await firstValueFrom(this.loadData$());
|
||||
this._loadingService.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,80 +1,60 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { EntitiesService } from '@iqser/common-ui';
|
||||
import { ComponentMapping, IComponentMapping } from '@red/domain';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { EntitiesService, QueryParam } from '@iqser/common-ui';
|
||||
import { ComponentMapping, IComponentMapping, IComponentMappingList } from '@red/domain';
|
||||
import { Observable } from 'rxjs';
|
||||
import { HeadersConfiguration, List } from '@common-ui/utils';
|
||||
|
||||
const DATA = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'OECD Number',
|
||||
file: 'some file name',
|
||||
delimiter: ',',
|
||||
encodingType: 'UTF-8',
|
||||
version: 2,
|
||||
searchKey: 'OECD Number',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Study Title',
|
||||
file: 'some file name',
|
||||
delimiter: ';',
|
||||
encodingType: 'ASCII',
|
||||
version: 1,
|
||||
searchKey: 'Study Title',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Report Number',
|
||||
file: 'some file name',
|
||||
delimiter: '.',
|
||||
encodingType: 'ISO',
|
||||
version: 2,
|
||||
searchKey: 'Report Number',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'GLP Study',
|
||||
file: 'some file name',
|
||||
delimiter: '"',
|
||||
encodingType: 'UTF-8',
|
||||
version: 5,
|
||||
searchKey: 'GLP Study',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Performing Laboratory',
|
||||
file: 'some file name',
|
||||
delimiter: ']',
|
||||
encodingType: 'UTF-8',
|
||||
version: 2,
|
||||
searchKey: 'Performing Laboratory',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
name: 'Test',
|
||||
file: 'some file name',
|
||||
delimiter: ';',
|
||||
encodingType: 'UTF-8',
|
||||
version: 3,
|
||||
searchKey: 'Test',
|
||||
},
|
||||
];
|
||||
interface CreateMappingParams {
|
||||
dossierTemplateId: string;
|
||||
name: string;
|
||||
encoding: string;
|
||||
delimiter: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ComponentMappingsService extends EntitiesService<IComponentMapping, ComponentMapping> {
|
||||
loadData(): Observable<ComponentMapping[]> {
|
||||
return of(DATA);
|
||||
getComponentMappings(dossierTemplateId: string): Observable<IComponentMappingList> {
|
||||
return this._http.get<IComponentMappingList>(`/api/dossier-templates/${dossierTemplateId}/component-mappings`);
|
||||
}
|
||||
|
||||
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;
|
||||
createComponentMapping(
|
||||
dossierTemplateId: string,
|
||||
componentMapping: Partial<ComponentMapping>,
|
||||
file: Blob,
|
||||
): Observable<IComponentMapping> {
|
||||
const formParams = new FormData();
|
||||
formParams.append('file', file);
|
||||
|
||||
const queryParams: List<QueryParam> = [
|
||||
{ key: 'name', value: componentMapping.name },
|
||||
{ key: 'encoding', value: componentMapping.encoding },
|
||||
{ key: 'delimiter', value: componentMapping.delimiter },
|
||||
];
|
||||
|
||||
if (componentMapping.id) {
|
||||
return this._http.put<IComponentMapping>(
|
||||
`/api/dossier-templates/${dossierTemplateId}/component-mappings/${componentMapping.id}`,
|
||||
formParams,
|
||||
{
|
||||
params: this._queryParams(queryParams),
|
||||
},
|
||||
);
|
||||
}
|
||||
DATA.push(mapping);
|
||||
return of(mapping);
|
||||
|
||||
return this._http.post<IComponentMapping>(`/api/dossier-templates/${dossierTemplateId}/component-mappings`, formParams, {
|
||||
params: this._queryParams(queryParams),
|
||||
});
|
||||
}
|
||||
|
||||
deleteComponentMapping(dossierTemplateId: string, componentMappingId: string) {
|
||||
return this._http.delete(`/api/dossier-templates/${dossierTemplateId}/component-mappings/${componentMappingId}`);
|
||||
}
|
||||
|
||||
getComponentMappingFile(dossierTemplateId: string, componentMappingId: string) {
|
||||
return this._http.get(`/api/dossier-templates/${dossierTemplateId}/component-mappings/${componentMappingId}`, {
|
||||
responseType: 'text',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 3a9f36e71b184e66eb791af19deeb258f8ec333d
|
||||
Subproject commit 5eef6d403a57c224eec836d9d98787c6a128c50a
|
||||
@ -0,0 +1,16 @@
|
||||
import { ComponentMapping, IComponentMapping } from './component-mapping';
|
||||
|
||||
export interface IComponentMappingList {
|
||||
dossierTemplateId: string;
|
||||
componentMappingList: IComponentMapping[];
|
||||
}
|
||||
|
||||
export class ComponentMappingList implements IComponentMappingList {
|
||||
readonly dossierTemplateId: string;
|
||||
readonly componentMappingList: ComponentMapping[];
|
||||
|
||||
constructor(componentMappingList: IComponentMappingList) {
|
||||
this.dossierTemplateId = componentMappingList.dossierTemplateId;
|
||||
this.componentMappingList = componentMappingList.componentMappingList;
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
import { IComponentMapping } from './component-mapping';
|
||||
import { IListable } from '@iqser/common-ui';
|
||||
|
||||
export class ComponentMapping implements IComponentMapping, IListable {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly file: string;
|
||||
readonly delimiter: string;
|
||||
readonly encodingType: string;
|
||||
readonly version: number;
|
||||
|
||||
constructor(componentMapping: IComponentMapping) {
|
||||
this.id = componentMapping.id;
|
||||
this.name = componentMapping.name;
|
||||
this.file = componentMapping.file;
|
||||
this.delimiter = componentMapping.delimiter;
|
||||
this.encodingType = componentMapping.encodingType;
|
||||
this.version = componentMapping.version;
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,38 @@
|
||||
export interface IComponentMapping {
|
||||
import { IListable } from '@iqser/common-ui';
|
||||
|
||||
export interface IComponentMapping extends IListable {
|
||||
id: string;
|
||||
name: string;
|
||||
file: string;
|
||||
fileName: string;
|
||||
version: number;
|
||||
columnLabels: string[];
|
||||
numberOfLines: number;
|
||||
encoding: string;
|
||||
delimiter: string;
|
||||
encodingType: string;
|
||||
}
|
||||
|
||||
export class ComponentMapping implements IComponentMapping, IListable {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly fileName: string;
|
||||
readonly version: number;
|
||||
readonly columnLabels: string[];
|
||||
readonly numberOfLines: number;
|
||||
readonly encoding: string;
|
||||
readonly delimiter: string;
|
||||
|
||||
constructor(componentMapping: IComponentMapping) {
|
||||
this.id = componentMapping.id;
|
||||
this.name = componentMapping.name;
|
||||
this.fileName = componentMapping.fileName;
|
||||
this.version = componentMapping.version;
|
||||
this.columnLabels = componentMapping.columnLabels;
|
||||
this.numberOfLines = componentMapping.numberOfLines;
|
||||
this.encoding = componentMapping.encoding;
|
||||
this.delimiter = componentMapping.delimiter;
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export * from './component-mapping.model';
|
||||
export * from './component-mapping-list.model';
|
||||
export * from './component-mapping';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user