Skip to content

Commit f3a64bc

Browse files
committed
Implement vocabulary selector for new fields input
1 parent a5512f0 commit f3a64bc

3 files changed

Lines changed: 94 additions & 6 deletions

File tree

src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ import { ConfidenceType } from 'src/app/core/shared/confidence-type';
2323
import { DynamicOneboxModel } from 'src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.model';
2424
import { Observable } from 'rxjs';
2525
import { DynamicScrollableDropdownModel } from 'src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
26+
import { RegistryService } from 'src/app/core/registry/registry.service';
27+
import { NotificationsService } from 'src/app/shared/notifications/notifications.service';
28+
import { createPaginatedList } from 'src/app/shared/testing/utils.test';
29+
import { MetadataField } from 'src/app/core/metadata/metadata-field.model';
30+
import { MetadataSchema } from 'src/app/core/metadata/metadata-schema.model';
2631

2732
const EDIT_BTN = 'edit';
2833
const CONFIRM_BTN = 'confirm';
@@ -38,6 +43,8 @@ describe('DsoEditMetadataValueComponent', () => {
3843
let dsoNameService: DSONameService;
3944
let vocabularyServiceStub: any;
4045
let itemService: ItemDataService;
46+
let registryService: RegistryService;
47+
let notificationsService: NotificationsService;
4148

4249
let editMetadataValue: DsoEditMetadataValue;
4350
let metadataValue: MetadataValue;
@@ -107,7 +114,24 @@ describe('DsoEditMetadataValueComponent', () => {
107114
}
108115
};
109116

117+
let metadataSchema: MetadataSchema;
118+
let metadataFields: MetadataField[];
119+
110120
function initServices(): void {
121+
metadataSchema = Object.assign(new MetadataSchema(), {
122+
id: 0,
123+
prefix: 'metadata',
124+
namespace: 'http://example.com/',
125+
});
126+
metadataFields = [
127+
Object.assign(new MetadataField(), {
128+
id: 0,
129+
element: 'regular',
130+
qualifier: null,
131+
schema: createSuccessfulRemoteDataObject$(metadataSchema),
132+
}),
133+
];
134+
111135
relationshipService = jasmine.createSpyObj('relationshipService', {
112136
resolveMetadataRepresentation: of(new ItemMetadataRepresentation(metadataValue)),
113137
});
@@ -118,6 +142,10 @@ describe('DsoEditMetadataValueComponent', () => {
118142
findByHref: createSuccessfulRemoteDataObject$(item)
119143
});
120144
vocabularyServiceStub = new VocabularyServiceStub();
145+
registryService = jasmine.createSpyObj('registryService', {
146+
queryMetadataFields: createSuccessfulRemoteDataObject$(createPaginatedList(metadataFields)),
147+
});
148+
notificationsService = jasmine.createSpyObj('notificationsService', ['error', 'success']);
121149
}
122150

123151
beforeEach(waitForAsync(() => {
@@ -143,7 +171,9 @@ describe('DsoEditMetadataValueComponent', () => {
143171
{ provide: RelationshipDataService, useValue: relationshipService },
144172
{ provide: DSONameService, useValue: dsoNameService },
145173
{ provide: VocabularyService, useValue: vocabularyServiceStub },
146-
{ provide: ItemDataService, useValue: itemService }
174+
{ provide: ItemDataService, useValue: itemService },
175+
{ provide: RegistryService, useValue: registryService },
176+
{ provide: NotificationsService, useValue: notificationsService },
147177
],
148178
schemas: [NO_ERRORS_SCHEMA]
149179
}).compileComponents();

src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.ts

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
1+
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
22
import { DsoEditMetadataChangeType, DsoEditMetadataValue } from '../dso-edit-metadata-form';
33
import { Observable } from 'rxjs/internal/Observable';
44
import {
@@ -8,7 +8,7 @@ import {
88
import { RelationshipDataService } from '../../../core/data/relationship-data.service';
99
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
1010
import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model';
11-
import { map, switchMap } from 'rxjs/operators';
11+
import { map, switchMap, take } from 'rxjs/operators';
1212
import { getItemPageRoute } from '../../../item-page/item-page-routing-paths';
1313
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
1414
import { EMPTY } from 'rxjs/internal/observable/empty';
@@ -17,7 +17,7 @@ import { Vocabulary } from '../../../core/submission/vocabularies/models/vocabul
1717
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
1818
import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model';
1919
import { ConfidenceType } from '../../../core/shared/confidence-type';
20-
import { getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload, getRemoteDataPayload } from '../../../core/shared/operators';
20+
import { getFirstCompletedRemoteData, getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload, getRemoteDataPayload, metadataFieldsToString } from '../../../core/shared/operators';
2121
import { DsDynamicOneboxModelConfig, DynamicOneboxModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.model';
2222
import { DynamicScrollableDropdownModel, DynamicScrollableDropdownModelConfig } from '../../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model';
2323
import { ItemDataService } from '../../../core/data/item-data.service';
@@ -27,6 +27,9 @@ import { Collection } from '../../../core/shared/collection.model';
2727
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
2828
import { isNotEmpty } from '../../../shared/empty.util';
2929
import { of as observableOf } from 'rxjs';
30+
import { RegistryService } from 'src/app/core/registry/registry.service';
31+
import { TranslateService } from '@ngx-translate/core';
32+
import { NotificationsService } from 'src/app/shared/notifications/notifications.service';
3033

3134
@Component({
3235
selector: 'ds-dso-edit-metadata-value',
@@ -36,7 +39,7 @@ import { of as observableOf } from 'rxjs';
3639
/**
3740
* Component displaying a single editable row for a metadata value
3841
*/
39-
export class DsoEditMetadataValueComponent implements OnInit {
42+
export class DsoEditMetadataValueComponent implements OnInit, OnChanges {
4043
/**
4144
* The parent {@link DSpaceObject} to display a metadata form for
4245
* Also used to determine metadata-representations in case of virtual metadata
@@ -155,7 +158,11 @@ export class DsoEditMetadataValueComponent implements OnInit {
155158
constructor(protected relationshipService: RelationshipDataService,
156159
protected dsoNameService: DSONameService,
157160
protected vocabularyService: VocabularyService,
158-
protected itemService: ItemDataService) {
161+
protected itemService: ItemDataService,
162+
protected cdr: ChangeDetectorRef,
163+
protected registryService: RegistryService,
164+
protected notificationsService: NotificationsService,
165+
protected translate: TranslateService) {
159166
}
160167

161168
ngOnInit(): void {
@@ -275,6 +282,56 @@ export class DsoEditMetadataValueComponent implements OnInit {
275282
}));
276283
}
277284

285+
/**
286+
* Change callback for the component. Check if the mdField has changed to retrieve whether it is metadata
287+
* that uses a controlled vocabulary and update the related properties
288+
*
289+
* @param {SimpleChanges} changes
290+
*/
291+
ngOnChanges(changes: SimpleChanges): void {
292+
if (isNotEmpty(changes.mdField) && !changes.mdField.firstChange) {
293+
if (isNotEmpty(changes.mdField.currentValue) ) {
294+
if (isNotEmpty(changes.mdField.previousValue) &&
295+
changes.mdField.previousValue !== changes.mdField.currentValue) {
296+
// Clear authority value in case it has been assigned with the previous metadataField used
297+
this.mdValue.newValue.authority = null;
298+
this.mdValue.newValue.confidence = ConfidenceType.CF_UNSET;
299+
}
300+
301+
// Only ask if the current mdField have a period character to reduce request
302+
if (changes.mdField.currentValue.includes('.')) {
303+
this.validateMetadataField().subscribe((isValid: boolean) => {
304+
if (isValid) {
305+
this.initAuthorityProperties();
306+
this.cdr.detectChanges();
307+
}
308+
});
309+
}
310+
}
311+
}
312+
}
313+
314+
/**
315+
* Validate the metadata field to check if it exists on the server and return an observable boolean for success/error
316+
*/
317+
validateMetadataField(): Observable<boolean> {
318+
return this.registryService.queryMetadataFields(this.mdField, null, true, false, followLink('schema')).pipe(
319+
getFirstCompletedRemoteData(),
320+
switchMap((rd) => {
321+
if (rd.hasSucceeded) {
322+
return observableOf(rd).pipe(
323+
metadataFieldsToString(),
324+
take(1),
325+
map((fields: string[]) => fields.indexOf(this.mdField) > -1)
326+
);
327+
} else {
328+
this.notificationsService.error(this.translate.instant(`${this.dsoType}.edit.metadata.metadatafield.error`), rd.errorMessage);
329+
return [false];
330+
}
331+
}),
332+
);
333+
}
334+
278335
/**
279336
* Checks if this field use a authority vocabulary
280337
*/

src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
[dsoType]="dsoType"
4141
[saving$]="savingOrLoadingFieldValidation$"
4242
[isOnlyValue]="true"
43+
[mdField]="newMdField"
4344
(confirm)="confirmNewValue($event)"
4445
(remove)="form.newValue = undefined"
4546
(undo)="form.newValue = undefined">

0 commit comments

Comments
 (0)