381 lines
15 KiB
TypeScript
381 lines
15 KiB
TypeScript
|
|
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, SimpleChanges } from '@angular/core';
|
|
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
|
import { MatDialog } from "@angular/material/dialog";
|
|
import { DescriptionTemplateFieldType } from '@app/core/common/enum/description-template-field-type';
|
|
import { DescriptionTemplateFieldValidationType } from '@app/core/common/enum/description-template-field-validation-type';
|
|
import { DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateLabelAndMultiplicityData, DescriptionTemplateUploadData } from '@app/core/model/description-template/description-template';
|
|
import { StorageFile } from '@app/core/model/storage-file/storage-file';
|
|
import { DescriptionService } from '@app/core/services/description/description.service';
|
|
import { DmpService } from '@app/core/services/dmp/dmp.service';
|
|
import { SnackBarNotificationLevel, UiNotificationService } from "@app/core/services/notification/ui-notification-service";
|
|
import { ReferenceService } from '@app/core/services/reference/reference.service';
|
|
import { StorageFileService } from '@app/core/services/storage-file/storage-file.service';
|
|
import { TagService } from '@app/core/services/tag/tag.service';
|
|
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
|
|
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
|
|
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
|
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
|
import { BaseComponent } from '@common/base/base.component';
|
|
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
|
|
import { Guid } from '@common/types/guid';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
import * as FileSaver from 'file-saver';
|
|
import { Observable } from 'rxjs';
|
|
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
|
|
import { nameof } from 'ts-simple-nameof';
|
|
|
|
@Component({
|
|
selector: 'app-description-form-field',
|
|
templateUrl: './form-field.component.html',
|
|
styleUrls: ['./form-field.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush
|
|
})
|
|
export class DescriptionFormFieldComponent extends BaseComponent implements OnInit {
|
|
|
|
@Input() field: DescriptionTemplateField;
|
|
@Input() fieldSet: DescriptionTemplateFieldSet;
|
|
@Input() propertiesFormGroup: UntypedFormGroup;
|
|
@Input() visibilityRulesService: VisibilityRulesService;
|
|
isRequired: boolean = false;
|
|
|
|
@Input() datasetProfileId: any;
|
|
@Input() isChild: Boolean = false;
|
|
|
|
visible: boolean = true;
|
|
descriptionTemplateFieldTypeEnum = DescriptionTemplateFieldType;
|
|
|
|
|
|
|
|
public singleAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
|
public multipleAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
|
tagsAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
|
multipleReferenceAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
|
|
|
|
|
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
|
|
|
|
datasetIdInitialized: boolean = false;
|
|
|
|
validationIcon;
|
|
|
|
readonly datasetIdTypes: any[] = [
|
|
{ name: 'Handle', value: 'handle' },
|
|
{ name: 'DOI', value: 'doi' },
|
|
{ name: 'Ark', value: 'ark' },
|
|
{ name: 'Url', value: 'url' },
|
|
{ name: 'Other', value: 'other' }
|
|
];
|
|
|
|
|
|
readonly validationTypes: any[] = [
|
|
{ name: 'Zenodo', value: 'zenodo' }
|
|
];
|
|
|
|
filesToUpload: FileList;
|
|
fileNameDisplay: string = null;
|
|
|
|
constructor(
|
|
private language: TranslateService,
|
|
public dmpService: DmpService,
|
|
public descriptionService: DescriptionService,
|
|
public tagService: TagService,
|
|
private cdr: ChangeDetectorRef,
|
|
private uiNotificationService: UiNotificationService,
|
|
public dialog: MatDialog,
|
|
private fileUtils: FileUtils,
|
|
private referenceService: ReferenceService,
|
|
private storageFileService: StorageFileService
|
|
) {
|
|
super();
|
|
}
|
|
|
|
ngOnChanges(changes: SimpleChanges) {
|
|
if (changes['form']) {
|
|
}
|
|
}
|
|
|
|
ngOnInit() {
|
|
|
|
if(this.field?.data?.fieldType == DescriptionTemplateFieldType.UPLOAD && this.field && this.field.id && (this.propertiesFormGroup?.get(this.field.id).get('textValue').value != undefined) && !this.fileNameDisplay) {
|
|
const id = Guid.parse((this.propertiesFormGroup?.get(this.field.id).get('textValue').value as string));
|
|
|
|
const fields = [
|
|
nameof<StorageFile>(x => x.id),
|
|
nameof<StorageFile>(x => x.name),
|
|
nameof<StorageFile>(x => x.extension),
|
|
]
|
|
|
|
this.storageFileService.getSingle(id, fields).pipe(takeUntil(this._destroyed)).subscribe(storageFile => {
|
|
this.createFileNameDisplay(storageFile.name, storageFile.extension);
|
|
this.applyFieldType();
|
|
});
|
|
} else {
|
|
this.applyFieldType();
|
|
}
|
|
}
|
|
|
|
checkBoxChanged(event: MatCheckboxChange){
|
|
if (event.checked){
|
|
this.propertiesFormGroup?.get(this.field.id).get('textValue').setValue("true");
|
|
} else{
|
|
this.propertiesFormGroup?.get(this.field.id).get('textValue').setValue("false");
|
|
}
|
|
this.visibilityRulesService.reloadVisibility();
|
|
}
|
|
|
|
private applyFieldType(){
|
|
this.isRequired = this.field.validations?.includes(DescriptionTemplateFieldValidationType.Required);
|
|
|
|
switch (this.field?.data?.fieldType) {
|
|
// case DescriptionTemplateFieldType.EXTERNAL_DATASETS:
|
|
// //TODO: refactor
|
|
// // this.multipleReferenceAutoCompleteConfiguration = {
|
|
// // filterFn: this.filterOrganisations.bind(this),
|
|
// // initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
|
|
// // displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
|
// // titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
|
// // subtitleFn: (item) => { try { return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } catch { return '' } },
|
|
// // valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
|
// // };
|
|
// break;
|
|
case DescriptionTemplateFieldType.TAGS:
|
|
this.tagsAutoCompleteConfiguration = {
|
|
filterFn: this.filterTags.bind(this),
|
|
initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
|
|
displayFn: (item) => { try { return this.showTag(item) } catch { return '' } },
|
|
titleFn: (item) => { try { return item['name'] } catch { return '' } },
|
|
valueAssign: (item) => { try { return this.addTag(item) } catch { return '' } }
|
|
};
|
|
this.parseTags();
|
|
break;
|
|
|
|
case DescriptionTemplateFieldType.DATASET_IDENTIFIER:
|
|
// const value = this.propertiesFormGroup.get(this.field.id).get('value').value;
|
|
// const disabled = this.propertiesFormGroup.get(this.field.id).disabled;
|
|
//TODO: Refactor this.
|
|
// this.form.removeControl('value');
|
|
// this.form.addControl('value', new DatasetIdModel(value).buildForm());
|
|
// if (disabled) {
|
|
// this.form.disable();
|
|
// }
|
|
this.datasetIdInitialized = true;
|
|
break;
|
|
case DescriptionTemplateFieldType.VALIDATION:
|
|
// const value1 = this.propertiesFormGroup.get(this.field.id).get('value').value;
|
|
// const disabled1 = this.propertiesFormGroup.get(this.field.id).disabled;
|
|
//TODO: Refactor this.
|
|
// this.form.removeControl('value');
|
|
// this.form.addControl('value', new DatasetIdModel(value1).buildForm());
|
|
// if (disabled1) {
|
|
// this.form.disable();
|
|
// }
|
|
break;
|
|
case DescriptionTemplateFieldType.CHECK_BOX:
|
|
if (this.propertiesFormGroup?.get(this.field.id).get('textValue').value == undefined) this.propertiesFormGroup?.get(this.field.id).get('textValue').setValue("false");
|
|
this.visibilityRulesService.reloadVisibility();
|
|
break;
|
|
}
|
|
|
|
// this.form = this.visibilityRulesService.getFormGroup(this.field.id);
|
|
|
|
//TODO: refactor
|
|
this.propertiesFormGroup.get(this.field.id).valueChanges
|
|
.pipe(
|
|
takeUntil(this._destroyed),
|
|
distinctUntilChanged()
|
|
)
|
|
.subscribe(item => {
|
|
this.visibilityRulesService.updateVisibilityForSource(this.field?.id);
|
|
});
|
|
}
|
|
|
|
makeAutocompleteConfiguration(myfunc: Function, title: string, subtitle?: string): void {
|
|
if (!((this.field.data as DescriptionTemplateLabelAndMultiplicityData).multipleSelect)) {
|
|
this.singleAutoCompleteConfiguration = {
|
|
filterFn: myfunc.bind(this),
|
|
initialItems: (extraData) => myfunc(''),
|
|
displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item)[title] : item[title] } catch { return '' } },
|
|
titleFn: (item) => { try { return item[title] } catch { return '' } },
|
|
valueAssign: (item) => JSON.stringify(item),
|
|
subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } }
|
|
};
|
|
}
|
|
else {
|
|
this.multipleAutoCompleteConfiguration = {
|
|
filterFn: myfunc.bind(this),
|
|
initialItems: (extraData) => myfunc(''),
|
|
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } },
|
|
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } },
|
|
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } },
|
|
subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } }
|
|
}
|
|
}
|
|
}
|
|
|
|
parseTags() {
|
|
try {
|
|
|
|
|
|
let stringValue = this.propertiesFormGroup.get(this.field.id).get('value').value;
|
|
if (typeof stringValue === 'string') {
|
|
stringValue = (<string>stringValue).replace(new RegExp('{', 'g'), '{"').replace(new RegExp('=', 'g'), '":"').replace(new RegExp(',', 'g'), '",').replace(new RegExp(', ', 'g'), ', "').replace(new RegExp('}', 'g'), '"}');
|
|
stringValue = stringValue.replace(new RegExp('}"', 'g'), '}').replace(new RegExp('"{', 'g'), '{');
|
|
} else if (stringValue instanceof Array) {
|
|
const tempArray = new Array();
|
|
for (let stringTag of stringValue) {
|
|
tempArray.push(JSON.parse(stringTag));
|
|
}
|
|
stringValue = JSON.stringify(tempArray);
|
|
}
|
|
const tagArray = JSON.parse(stringValue);
|
|
this.propertiesFormGroup.get(this.field.id).get('value').patchValue(tagArray);
|
|
} catch (e) {
|
|
console.warn('Could not parse tags');
|
|
}
|
|
}
|
|
|
|
filterTags(value: string): Observable<any[]> {
|
|
//TODO refactor
|
|
return null;
|
|
// const requestItem: RequestItem<TagCriteria> = new RequestItem();
|
|
// const criteria: TagCriteria = new TagCriteria();
|
|
// criteria.like = value;
|
|
// requestItem.criteria = criteria;
|
|
// return this.externalSourcesService.searchDatasetTags(requestItem);
|
|
}
|
|
|
|
showTag(ev: any) {
|
|
if (typeof ev === 'string') {
|
|
return ev;
|
|
} else {
|
|
return ev.name;
|
|
}
|
|
}
|
|
|
|
addTag(ev: any) {
|
|
// let item: ExternalTagEditorModel;
|
|
// //this.filteredTags = this.formGroup.get('tags').value;
|
|
// if (typeof ev === 'string') {
|
|
// item = new ExternalTagEditorModel('', ev);
|
|
// } else {
|
|
// item = ev;
|
|
// }
|
|
// if (item.name !== '') {
|
|
// return item;
|
|
// }
|
|
}
|
|
|
|
getDatasetIdControl(name: string): UntypedFormControl {
|
|
return this.propertiesFormGroup.get(this.field.id).get(name) as UntypedFormControl;
|
|
}
|
|
|
|
validateId() {
|
|
//TODO refactor
|
|
return null;
|
|
// const identifier = this.getDatasetIdControl('identifier').value;
|
|
// const type = this.getDatasetIdControl('type').value;
|
|
// this.validationIcon = 'loading';
|
|
// this.externalSourcesService.validateIdentifier(identifier, type).pipe(takeUntil(this._destroyed)).subscribe(result => {
|
|
// this.validationIcon = result === true ? 'done' : 'clear';
|
|
// });
|
|
|
|
}
|
|
|
|
|
|
public upload() {
|
|
this.storageFileService.uploadTempFiles(this.filesToUpload[0])
|
|
.pipe(takeUntil(this._destroyed)).subscribe((response) => {
|
|
this.propertiesFormGroup?.get(this.field.id).get('textValue').patchValue(response[0].id.toString());
|
|
this.createFileNameDisplay(response[0].name, response[0].extension);
|
|
this.cdr.detectChanges();
|
|
}, error => {
|
|
this.onCallbackUploadFail(error.error);
|
|
})
|
|
|
|
|
|
}
|
|
|
|
private createFileNameDisplay(name: string, extension: string){
|
|
if (extension.startsWith('.')) this.fileNameDisplay = name + extension;
|
|
else this.fileNameDisplay = name + '.' + extension;
|
|
}
|
|
|
|
|
|
private onCallbackUploadFail(error: any) {
|
|
this.makeFilesNull();
|
|
this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error);
|
|
}
|
|
|
|
fileChangeEvent(fileInput: any, dropped: boolean = false) {
|
|
|
|
if (dropped) {
|
|
this.filesToUpload = fileInput.addedFiles;
|
|
} else {
|
|
this.filesToUpload = fileInput.target.files;
|
|
}
|
|
|
|
|
|
let messages: string[] = [];
|
|
if (this.filesToUpload.length == 0) {
|
|
messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.NO-FILES-SELECTED'));
|
|
return;
|
|
} else {
|
|
let fileToUpload = this.filesToUpload[0];
|
|
const data = this.field.data as DescriptionTemplateUploadData;
|
|
if (data && data.types
|
|
&& data.types.map(type => type.value).includes(fileToUpload.type)
|
|
&& data.maxFileSizeInMB
|
|
&& data.maxFileSizeInMB * 1048576 >= fileToUpload.size) {
|
|
this.upload();
|
|
} else {
|
|
this.filesToUpload = null;
|
|
messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.LARGE-FILE-OR-UNACCEPTED-TYPE'));
|
|
messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.MAX-FILE-SIZE', { 'maxfilesize': data.maxFileSizeInMB }));
|
|
messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.ACCEPTED-FILE-TRANSFOMER') + data.types.map(type => type.value).join(", "));
|
|
}
|
|
|
|
if (messages && messages.length > 0) {
|
|
this.dialog.open(FormValidationErrorsDialogComponent, {
|
|
data: {
|
|
errorMessages: messages
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
onRemove(makeFilesNull: boolean = true) {
|
|
this.makeFilesNull()
|
|
this.cdr.detectChanges();
|
|
|
|
}
|
|
|
|
makeFilesNull() {
|
|
this.filesToUpload = null;
|
|
this.propertiesFormGroup?.get(this.field.id).get('textValue').patchValue(null);
|
|
this.fileNameDisplay = null;
|
|
}
|
|
|
|
typesToString() {
|
|
return (this.field.data as DescriptionTemplateUploadData).types.map(type => type.value).toString();
|
|
}
|
|
|
|
download(): void {
|
|
|
|
if (this.propertiesFormGroup?.get(this.field.id).get('textValue').value) {
|
|
const id = Guid.parse((this.propertiesFormGroup?.get(this.field.id).get('textValue').value as string));
|
|
|
|
this.storageFileService.download(id).pipe(takeUntil(this._destroyed))
|
|
.subscribe(response => {
|
|
const blob = new Blob([response.body]);
|
|
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
|
FileSaver.saveAs(blob, filename);
|
|
});
|
|
}
|
|
|
|
}
|
|
}
|