diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index c2503f871..7062c1f82 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -9,14 +9,7 @@ import { ReloadHelperComponent } from './ui/misc/reload-helper/reload-helper.com const appRoutes: Routes = [ { path: '', - component: AppComponent, - data: { - breadcrumbs: false, - title: 'GENERAL.TITLES.GENERAL', - ...BreadcrumbService.generateRouteDataConfiguration({ - title: 'BREADCRUMBS.HOME' - }) - }, + redirectTo:'home', pathMatch: 'full' }, { diff --git a/dmp-frontend/src/app/core/model/description/description.ts b/dmp-frontend/src/app/core/model/description/description.ts index 781672c47..39f61604b 100644 --- a/dmp-frontend/src/app/core/model/description/description.ts +++ b/dmp-frontend/src/app/core/model/description/description.ts @@ -78,7 +78,6 @@ export interface DescriptionPersist extends BaseEntityPersist { description: string; properties: DescriptionPropertyDefinitionPersist; tags: string[]; - references: DescriptionReferencePersist[]; } export interface DescriptionPropertyDefinitionPersist { diff --git a/dmp-frontend/src/app/core/services/reference/reference.service.ts b/dmp-frontend/src/app/core/services/reference/reference.service.ts index fdca0d1ea..bca337b17 100644 --- a/dmp-frontend/src/app/core/services/reference/reference.service.ts +++ b/dmp-frontend/src/app/core/services/reference/reference.service.ts @@ -122,11 +122,11 @@ export class ReferenceService { return { initialItems: (data?: any) => this.searchWithDefinition(this.buildAutocompleteSearchLookup(typeId)).pipe(map(x => x)), filterFn: (searchQuery: string, data?: any) => this.searchWithDefinition(this.buildAutocompleteSearchLookup(typeId, searchQuery)).pipe(map(x => x)), - getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteSearchSelectedItemsLookup([typeId], null, null, null, [selectedItem])).pipe(map(x => x.items[0])), displayFn: (item: Reference) => item.label, subtitleFn: (item: Reference) => item?.sourceType === ReferenceSourceType.External ? this.language.instant('REFERENCE-FIELD-COMPONENT.EXTERNAL-SOURCE') + ': ' + item.source : this.language.instant('REFERENCE-FIELD-COMPONENT.INTERNAL-SOURCE'), titleFn: (item: Reference) => item.label, valueAssign: (item: Reference) => item, + uniqueAssign: (item: Reference) => item.source + '_' + item.reference, }; }; @@ -134,7 +134,6 @@ export class ReferenceService { return { initialItems: (excludedItems: any[], data?: any) => this.searchWithDefinition(this.buildAutocompleteSearchLookup(typeId, null)).pipe(map(x => x)), filterFn: (searchQuery: string, excludedItems: any[]) => this.searchWithDefinition(this.buildAutocompleteSearchLookup(typeId, searchQuery)).pipe(map(x => x)), - getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteSearchSelectedItemsLookup([typeId], null, null, null, selectedItems?.map(x => x.id))).pipe(map(x => x.items)), displayFn: (item: Reference) => item.label, titleFn: (item: Reference) => item.label, subtitleFn: (item: Reference) => item?.sourceType === ReferenceSourceType.External ? this.language.instant('REFERENCE-FIELD-COMPONENT.EXTERNAL-SOURCE') + ': ' + item.source : this.language.instant('REFERENCE-FIELD-COMPONENT.INTERNAL-SOURCE'), diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts index 85a57e34e..33ec75ee1 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete-configuration.ts @@ -28,7 +28,7 @@ export interface MultipleAutoCompleteConfiguration { extraData?: any; // Callback to intercept value assignment based on item selection valueAssign?: (selectedItem: any) => any; - // Callback to intercept value assignment based on item selection + // Callback to provide equals function betwen the values uniqueAssign?: (selectedItem: any) => any; // Property formating template optionTemplate?: TemplateRef; diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html index ec2eb9978..13f0f7406 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.html @@ -8,7 +8,7 @@ }" /> {{_displayFn(selectedItem)}} - diff --git a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts index 41ebb702b..920d1d346 100644 --- a/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/multiple/multiple-auto-complete.component.ts @@ -1,5 +1,5 @@ import { FocusMonitor } from '@angular/cdk/a11y'; -import { BACKSPACE, ENTER } from '@angular/cdk/keycodes'; +import { ENTER } from '@angular/cdk/keycodes'; import { Component, DoCheck, @@ -27,9 +27,8 @@ import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; import { BaseComponent } from '@common/base/base.component'; -import { isNullOrUndefined } from '@swimlane/ngx-datatable'; -import { BehaviorSubject, Observable, Subject, Subscription, combineLatest, interval, of as observableOf, of } from 'rxjs'; -import { catchError, debounceTime, delayWhen, distinctUntilChanged, map, mergeMap, startWith, switchMap, take, takeUntil, tap } from 'rxjs/operators'; +import { BehaviorSubject, Observable, Subject, interval, of as observableOf, of } from 'rxjs'; +import { catchError, debounceTime, delayWhen, distinctUntilChanged, map, mergeMap, startWith, switchMap, take, takeUntil } from 'rxjs/operators'; export class CustomComponentBase extends BaseComponent { constructor( diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts index b97d76151..0ba5cccf0 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete-configuration.ts @@ -27,6 +27,8 @@ export interface SingleAutoCompleteConfiguration { extraData?: any; // Callback to intercept value assignment based on item selection valueAssign?: (selectedItem: any) => any; + // Callback to provide equals function betwen the values + uniqueAssign?: (selectedItem: any) => any; // Property formating template optionTemplate?: TemplateRef; // Selected value formating template @@ -38,4 +40,5 @@ export interface SingleAutoCompleteConfiguration { // forceFocus?: boolean; autoSelectFirstOptionOnBlur?: boolean; + } diff --git a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts index f9c887828..8e5bdfbda 100644 --- a/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts +++ b/dmp-frontend/src/app/library/auto-complete/single/single-auto-complete.component.ts @@ -136,7 +136,7 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple ngOnChanges(changes: SimpleChanges) { if (changes['initialSelectedData'] && changes['initialSelectedData'].currentValue && changes['initialSelectedData'].isFirstChange && this.configuration != null) { - this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(this.initialSelectedData) : this.initialSelectedData), this.initialSelectedData); + this._selectedItems.set(this.selectedItemKey(this.initialSelectedData), this.initialSelectedData); this.inputValue = this._displayFn(this.initialSelectedData); } @@ -150,16 +150,16 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple } getSelectedItems(value: any) { - if (value != null && !this._selectedItems.has(JSON.stringify(value)) && this.configuration) { + if (value != null && !this._selectedItems.has(this.selectedItemKey(value)) && this.configuration) { if (this.configuration.getSelectedItem != null) { this.configuration.getSelectedItem(value).pipe(takeUntil(this._destroyed)).subscribe(x => { if (x != null) { - this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(x) : x), x); + this._selectedItems.set(this.selectedItemKey(x), x); this.inputValue = this._displayFn(x); } }); } else { - this._selectedItems.set(JSON.stringify(this.configuration.valueAssign != null ? this.configuration.valueAssign(value) : value), value); + this._selectedItems.set(this.selectedItemKey(value), value); this.inputValue = this._displayFn(value); } } @@ -204,7 +204,7 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple const newValue = this._valueToAssign(item); //Update selected items - this._selectedItems.set(JSON.stringify(newValue), item); + this._selectedItems.set(JSON.stringify(this.configuration.uniqueAssign != null ? this.configuration.uniqueAssign(newValue) : newValue), item); this._setValue(newValue); @@ -244,7 +244,7 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple public onBlur($event: MouseEvent) { if (this.value != null) { const inputLabel = this.inputValue; - const selectedLabel = this._displayFn(this._selectedItems.get(JSON.stringify(this.value))); + const selectedLabel = this._displayFn(this._selectedItems.get(this.selectedItemKey(this.value))); if (inputLabel && selectedLabel !== inputLabel) { this.inputValue = selectedLabel; } @@ -343,6 +343,12 @@ export class SingleAutoCompleteComponent extends _CustomComponentMixinBase imple return this.configuration.popupItemActionIcon != null ? this.configuration.popupItemActionIcon : ''; } + private selectedItemKey(item: any) { + return JSON.stringify( + this.configuration.uniqueAssign != null ? this.configuration.uniqueAssign(item) : + this.configuration.valueAssign != null ? this.configuration.valueAssign(item) : item + ) + } // get forceFocus(): boolean { // return this.configuration.forceFocus != null ? this.configuration.forceFocus : false; // } diff --git a/dmp-frontend/src/app/ui/auth/login/login.component.ts b/dmp-frontend/src/app/ui/auth/login/login.component.ts index 5969d96a2..f0531cbc1 100644 --- a/dmp-frontend/src/app/ui/auth/login/login.component.ts +++ b/dmp-frontend/src/app/ui/auth/login/login.component.ts @@ -31,17 +31,15 @@ export class LoginComponent extends BaseComponent implements OnInit { ngOnInit(): void { this.returnUrl = this.route.snapshot.queryParamMap.get('returnUrl') || '/'; if (!this.keycloakService.isLoggedIn()) { - this.authService.authenticate('/'); + this.authService.authenticate(this.returnUrl); } else { + if (!this.authService.selectedTenant()) { + this.authService.selectedTenant('default'); + } this.authService.prepareAuthRequest(from(this.keycloakService.getToken())).pipe(takeUntil(this._destroyed)).subscribe( () => { let returnUrL = this.returnUrl; let queryParams: Params = {}; - if (!this.authService.selectedTenant()) { - this.authService.selectedTenant('default'); - // returnUrL = '/login/post'; - // queryParams.returnUrl = this.returnUrl; - } this.zone.run(() => this.router.navigate([returnUrL], { queryParams })); }, (error) => this.authService.authenticate('/')); diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts index 129bd88a5..4f70e929b 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts @@ -19,7 +19,6 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti description: string; properties: DescriptionPropertyDefinitionEditorModel = new DescriptionPropertyDefinitionEditorModel(this.validationErrorModel); tags: string[] = []; - references: DescriptionReferenceEditorModel[]; permissions: string[]; public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); @@ -38,7 +37,6 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti this.description = item.description; this.tags = item.descriptionTags?.map(x => x.tag?.label); this.properties = new DescriptionPropertyDefinitionEditorModel(this.validationErrorModel).fromModel(item.properties, descriptionTemplate, item.descriptionReferences); - //if (item.references) { item.references.map(x => this.references.push(new DescriptionReferenceEditorModel().fromModel(x))); } } return this; } @@ -430,34 +428,30 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist { this.textListValue = item.textListValue; this.dateValue = item.dateValue; - this.reference = descriptionReferences?.filter(x => descriptionTemplateField.data.multipleSelect == false && x.data?.fieldId == descriptionTemplateField?.id && x.isActive == IsActive.Active).map(x => { - return { - id: x.reference.id, - label: x.reference.label, - reference: x.reference.reference, - source: x.reference.source, - typeId: x.reference.type.id, - description: x.reference.source, - definition: x.reference.definition, - abbreviation: x.reference.abbreviation, - sourceType: x.reference.sourceType - } - })[0]; + const references = descriptionReferences?.filter(x => x.data?.fieldId == descriptionTemplateField?.id && x.isActive == IsActive.Active).map(x => { + return { + id: x.reference.id, + label: x.reference.label, + reference: x.reference.reference, + source: x.reference.source, + typeId: x.reference.type.id, + description: x.reference.source, + definition: x.reference.definition, + abbreviation: x.reference.abbreviation, + sourceType: x.reference.sourceType + } + }); + if (descriptionTemplateField.data.multipleSelect == true) { + this.references = references; + } else { + if (references?.length == 1) this.reference = references[0]; + if (references?.length > 1) { + console.error("multiple references on single reference field: " + references); + this.reference = references[0]; + } + } + - this.references = descriptionReferences?.filter(x => x.data?.fieldId == descriptionTemplateField?.id && x.isActive == IsActive.Active).map(x => { - return { - id: x.reference.id, - label: x.reference.label, - reference: x.reference.reference, - source: x.reference.source, - typeId: x.reference.type.id, - description: x.reference.source, - definition: x.reference.definition, - abbreviation: x.reference.abbreviation, - sourceType: x.reference.sourceType - } - }); - this.externalIdentifier = new DescriptionExternalIdentifierEditorModel(this.validationErrorModel).fromModel(item.externalIdentifier); } return this; diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts index cb2e396ff..cf487ff8b 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts @@ -6,7 +6,6 @@ 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 { FetcherReference } from '@app/core/model/reference/reference'; 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'; @@ -33,17 +32,10 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn @Input() visibilityRulesService: VisibilityRulesService; isRequired: boolean = false; - - // @Input() field: Field; - // @Input() form: UntypedFormGroup; @Input() datasetProfileId: any; @Input() isChild: Boolean = false; visible: boolean = true; - - // change: Subscription; - // trackByFn = (index, item) => item ? item['id'] : null; - descriptionTemplateFieldTypeEnum = DescriptionTemplateFieldType; @@ -57,8 +49,6 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - // tags: ExternalTagEditorModel[] = []; - datasetIdInitialized: boolean = false; validationIcon; @@ -97,49 +87,8 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn ngOnInit() { - // this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => { - // // console.log('getElementVisibilityMapObservable form field set'); - - // if (x[this.field.id]) { - // this.visible = x[this.field.id]; - // } else { - // this.visible = true; - // } - // }); - - //TODO: validate that this logic is correct. Validation contenxt path might need to be fixed. - // if (this.propertiesFormGroup.get(this.field.id).get('value') == null) { - // const item: DescriptionFieldEditorModel = new DescriptionFieldEditorModel(); - // item.key = this.field.id; - // this.propertiesFormGroup.addControl(this.field.id, item.buildForm()); - // } - - // if (this.propertiesFormGroup.get(this.field.id).get('value').value) { - // this.visibilityRulesService.updateValueAndVisibility(this.field?.id, this.propertiesFormGroup.get(this.field.id).get('value').value); - // } - this.isRequired = this.field.validations?.includes(DescriptionTemplateFieldValidationType.Required); - //TODO: refactor - // if (this.field?.data?.fieldType === DescriptionTemplateFieldType.SELECT) { - // if ((this.field.data as DescriptionTemplateSelectData).multipleSelect) { - // const originalValue = this.propertiesFormGroup.get(this.field.id).get('value').value; - // if (originalValue !== null && typeof originalValue === 'string') { - // let values = (this.propertiesFormGroup.get(this.field.id).get('value').value).slice(1, -1).split(', ').filter((value) => !value.includes('"')); - // let specialValue = (this.propertiesFormGroup.get(this.field.id).get('value').value).split('"').filter((value) => !value.startsWith('[') && !value.endsWith(']') && !values.includes(value) && value !== ', '); - // specialValue.forEach(value => values.push(value)); - // if (!originalValue.startsWith('[') && !originalValue.endsWith(']')) { - // values = undefined; - // values = [originalValue]; - // } - // this.propertiesFormGroup.get(this.field.id).get('value').patchValue(values); - // values.forEach(element => { - // this.visibilityRulesService.updateValueAndVisibility(this.field?.id, element); - // }); - // } - // } - // } - switch (this.field?.data?.fieldType) { case DescriptionTemplateFieldType.EXTERNAL_DATASETS: //TODO: refactor @@ -214,61 +163,6 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn }); } - // _optionRemove(event) { - // const array = JSON.parse(this.propertiesFormGroup.get(this.field.id).get('value').value); - // if (array) { - // const index = array.map(x => x.id).indexOf(event.id); - // if (index >= 0) { - // array.splice(index, 1); - // } - // this.propertiesFormGroup.get(this.field.id).get('value').patchValue(JSON.stringify(array)); - // } - // } - - searchFromAutocomplete(query: string) { - - //TODO refactor - return null; - // if (this.autocompleteOptions) { - // const autocompleteRequestItem: RequestItem = new RequestItem(); - // autocompleteRequestItem.criteria = new DatasetExternalAutocompleteOptionsCriteria(); - // //TODO: refactor this - // //autocompleteRequestItem.criteria.sources = this.autocompleteOptions; - // // autocompleteRequestItem.criteria.like = query; - // // return this.datasetExternalAutocompleteService.queryApi(autocompleteRequestItem); - // return null; - // } - // else { - // const autocompleteRequestItem: RequestItem = new RequestItem(); - // autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria(); - // let parseIdArray: string[] = this.field?.id.split('_'); - // if (parseIdArray.length > 1) { - // autocompleteRequestItem.criteria.fieldID = parseIdArray[parseIdArray.length - 1]; - // } else { - // autocompleteRequestItem.criteria.fieldID = this.field?.id; - // } - // if (typeof this.datasetProfileId === 'string') { - // autocompleteRequestItem.criteria.profileID = this.datasetProfileId; - // } - // else if (this.datasetProfileId != null) { - // autocompleteRequestItem.criteria.profileID = this.datasetProfileId.id; - // } - // autocompleteRequestItem.criteria.like = query; - // //TODO: refactor this - // // return this.datasetExternalAutocompleteService.queryAutocomplete(autocompleteRequestItem); - // return null; - // } - } - - searchResearchers(query: string) { - //TODO refactor - return null; - // const reasearcherAutocompleteRequestItem: RequestItem = new RequestItem(); - // reasearcherAutocompleteRequestItem.criteria = new ResearcherCriteria; - // reasearcherAutocompleteRequestItem.criteria.name = query; - // return this.externalSourcesService.searchDMPResearchers(reasearcherAutocompleteRequestItem); - } - searchDatasets(query: string) { //TODO refactor return null; @@ -314,36 +208,6 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn } } - searchDatasetExternalRegistries(query: string): Observable { - //TODO refactor - return null; - // const requestItem: RequestItem = new RequestItem(); - // requestItem.criteria = new RegistryCriteria(); - // requestItem.criteria.like = query; - // requestItem.criteria.type = ''; - // return this.externalSourcesService.listExternal(ReferenceType.Registries, requestItem.criteria.like, requestItem.criteria.type); - } - - searchDatasetExternalServices(query: string): Observable { - //TODO refactor - return null; - // const requestItem: RequestItem = new RequestItem(); - // requestItem.criteria = new ServiceCriteria(); - // requestItem.criteria.like = query; - // requestItem.criteria.type = ''; - // return this.externalSourcesService.listExternal(ReferenceType.Services, requestItem.criteria.like, requestItem.criteria.type); - } - - searchDatasetTags(query: string): Observable { - //TODO refactor - return null; - // const requestItem: RequestItem = new RequestItem(); - // requestItem.criteria = new TagCriteria(); - // requestItem.criteria.like = query; - // requestItem.criteria.type = ''; - // return this.externalSourcesService.searchDatasetTags(requestItem); - } - parseTags() { try {