From 8d25ba764ca76b7f8776a50eecd3d70ae862c5e6 Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Wed, 3 Jan 2024 11:05:19 +0100 Subject: [PATCH 1/9] Implement getVocabularyByMetadataAndCollection in VocabularyService --- .../vocabulary.data.service.spec.ts | 22 ++++++++++++++++ .../vocabularies/vocabulary.data.service.ts | 25 +++++++++++++++++++ .../vocabularies/vocabulary.service.spec.ts | 19 ++++++++++++++ .../vocabularies/vocabulary.service.ts | 17 +++++++++++++ .../shared/testing/vocabulary-service.stub.ts | 4 +++ 5 files changed, 87 insertions(+) diff --git a/src/app/core/submission/vocabularies/vocabulary.data.service.spec.ts b/src/app/core/submission/vocabularies/vocabulary.data.service.spec.ts index 4b35871418f..eecf86a2118 100644 --- a/src/app/core/submission/vocabularies/vocabulary.data.service.spec.ts +++ b/src/app/core/submission/vocabularies/vocabulary.data.service.spec.ts @@ -7,8 +7,16 @@ */ import { VocabularyDataService } from './vocabulary.data.service'; import { testFindAllDataImplementation } from '../../data/base/find-all-data.spec'; +import { FindListOptions } from '../../data/find-list-options.model'; +import { RequestParam } from '../../cache/models/request-param.model'; +import { createSuccessfulRemoteDataObject$ } from 'src/app/shared/remote-data.utils'; describe('VocabularyDataService', () => { + let service: VocabularyDataService; + service = initTestService(); + let restEndpointURL = 'https://rest.api/server/api/submission/vocabularies'; + let vocabularyByMetadataAndCollectionEndpoint = `${restEndpointURL}/search/byMetadataAndCollection?metadata=dc.contributor.author&collection=1234-1234`; + function initTestService() { return new VocabularyDataService(null, null, null, null); } @@ -17,4 +25,18 @@ describe('VocabularyDataService', () => { const initService = () => new VocabularyDataService(null, null, null, null); testFindAllDataImplementation(initService); }); + + describe('getVocabularyByMetadataAndCollection', () => { + it('search vocabulary by metadata and collection calls expected methods', () => { + spyOn((service as any).searchData, 'getSearchByHref').and.returnValue(vocabularyByMetadataAndCollectionEndpoint); + spyOn(service, 'findByHref').and.returnValue(createSuccessfulRemoteDataObject$(null)); + service.getVocabularyByMetadataAndCollection('dc.contributor.author', '1234-1234'); + const options = Object.assign(new FindListOptions(), { + searchParams: [Object.assign(new RequestParam('metadata', encodeURIComponent('dc.contributor.author'))), + Object.assign(new RequestParam('collection', encodeURIComponent('1234-1234')))] + }); + expect((service as any).searchData.getSearchByHref).toHaveBeenCalledWith('byMetadataAndCollection', options); + expect(service.findByHref).toHaveBeenCalledWith(vocabularyByMetadataAndCollectionEndpoint, true, true); + }); + }); }); diff --git a/src/app/core/submission/vocabularies/vocabulary.data.service.ts b/src/app/core/submission/vocabularies/vocabulary.data.service.ts index a67b67ced70..9215990decf 100644 --- a/src/app/core/submission/vocabularies/vocabulary.data.service.ts +++ b/src/app/core/submission/vocabularies/vocabulary.data.service.ts @@ -20,6 +20,8 @@ import { PaginatedList } from '../../data/paginated-list.model'; import { Injectable } from '@angular/core'; import { VOCABULARY } from './models/vocabularies.resource-type'; import { dataService } from '../../data/base/data-service.decorator'; +import { SearchDataImpl } from '../../data/base/search-data'; +import { RequestParam } from '../../cache/models/request-param.model'; /** * Data service to retrieve vocabularies from the REST server. @@ -27,7 +29,10 @@ import { dataService } from '../../data/base/data-service.decorator'; @Injectable() @dataService(VOCABULARY) export class VocabularyDataService extends IdentifiableDataService implements FindAllData { + protected searchByMetadataAndCollectionPath = 'byMetadataAndCollection'; + private findAllData: FindAllData; + private searchData: SearchDataImpl; constructor( protected requestService: RequestService, @@ -38,6 +43,7 @@ export class VocabularyDataService extends IdentifiableDataService i super('vocabularies', requestService, rdbService, objectCache, halService); this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive); + this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive); } /** @@ -57,4 +63,23 @@ export class VocabularyDataService extends IdentifiableDataService i public findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig[]): Observable>> { return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } + + /** + * Return the controlled vocabulary configured for the specified metadata and collection if any (/submission/vocabularies/search/{@link searchByMetadataAndCollectionPath}?metadata=<>&collection=<>) + * @param metadataField metadata field to search + * @param collectionUUID collection UUID where is configured the vocabulary + * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + * @param reRequestOnStale Whether or not the request should automatically be re- + * requested after the response becomes stale + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which + * {@link HALLink}s should be automatically resolved + */ + public getVocabularyByMetadataAndCollection(metadataField: string, collectionUUID: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable> { + const findListOptions = new FindListOptions(); + findListOptions.searchParams = [new RequestParam('metadata', encodeURIComponent(metadataField)), + new RequestParam('collection', encodeURIComponent(collectionUUID))]; + const href$ = this.searchData.getSearchByHref(this.searchByMetadataAndCollectionPath, findListOptions, ...linksToFollow); + return this.findByHref(href$, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } } diff --git a/src/app/core/submission/vocabularies/vocabulary.service.spec.ts b/src/app/core/submission/vocabularies/vocabulary.service.spec.ts index e8ff2b479d8..38824b3fac0 100644 --- a/src/app/core/submission/vocabularies/vocabulary.service.spec.ts +++ b/src/app/core/submission/vocabularies/vocabulary.service.spec.ts @@ -255,7 +255,9 @@ describe('VocabularyService', () => { spyOn((service as any).vocabularyDataService, 'findById').and.callThrough(); spyOn((service as any).vocabularyDataService, 'findAll').and.callThrough(); spyOn((service as any).vocabularyDataService, 'findByHref').and.callThrough(); + spyOn((service as any).vocabularyDataService, 'getVocabularyByMetadataAndCollection').and.callThrough(); spyOn((service as any).vocabularyDataService.findAllData, 'getFindAllHref').and.returnValue(observableOf(entriesRequestURL)); + spyOn((service as any).vocabularyDataService.searchData, 'getSearchByHref').and.returnValue(observableOf(searchRequestURL)); }); afterEach(() => { @@ -312,6 +314,23 @@ describe('VocabularyService', () => { expect(result).toBeObservable(expected); }); }); + + describe('getVocabularyByMetadataAndCollection', () => { + it('should proxy the call to vocabularyDataService.getVocabularyByMetadataAndCollection', () => { + scheduler.schedule(() => service.getVocabularyByMetadataAndCollection(metadata, collectionUUID)); + scheduler.flush(); + + expect((service as any).vocabularyDataService.getVocabularyByMetadataAndCollection).toHaveBeenCalledWith(metadata, collectionUUID, true, true); + }); + + it('should return a RemoteData for the object with the given metadata and collection', () => { + const result = service.getVocabularyByMetadataAndCollection(metadata, collectionUUID); + const expected = cold('a|', { + a: vocabularyRD + }); + expect(result).toBeObservable(expected); + }); + }); }); describe('vocabulary entries', () => { diff --git a/src/app/core/submission/vocabularies/vocabulary.service.ts b/src/app/core/submission/vocabularies/vocabulary.service.ts index 1ff5b30ee08..2dd2cc3792f 100644 --- a/src/app/core/submission/vocabularies/vocabulary.service.ts +++ b/src/app/core/submission/vocabularies/vocabulary.service.ts @@ -87,6 +87,23 @@ export class VocabularyService { return this.vocabularyDataService.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } + /** + * Return the controlled vocabulary configured for the specified metadata and collection if any + * @param metadataField metadata field to search + * @param collectionUUID collection UUID where is configured the vocabulary + * @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + * @param reRequestOnStale Whether or not the request should automatically be re- + * requested after the response becomes stale + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which + * {@link HALLink}s should be automatically resolved + * @return {Observable>} + * Return an observable that emits vocabulary object + */ + getVocabularyByMetadataAndCollection(metadataField: string, collectionUUID: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable> { + return this.vocabularyDataService.getVocabularyByMetadataAndCollection(metadataField, collectionUUID, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); + } + /** * Return the {@link VocabularyEntry} list for a given {@link Vocabulary} * diff --git a/src/app/shared/testing/vocabulary-service.stub.ts b/src/app/shared/testing/vocabulary-service.stub.ts index f6a578dd3df..a0f11303694 100644 --- a/src/app/shared/testing/vocabulary-service.stub.ts +++ b/src/app/shared/testing/vocabulary-service.stub.ts @@ -42,4 +42,8 @@ export class VocabularyServiceStub { findVocabularyById(id: string): Observable> { return; } + + getVocabularyByMetadataAndCollection(metadataField: string, collectionUUID: string): Observable> { + return createSuccessfulRemoteDataObject$(null); + } } From c596c6eb144d0c263cafbf8357e33f2df54c9c61 Mon Sep 17 00:00:00 2001 From: Toni Prieto Date: Wed, 3 Jan 2024 11:08:07 +0100 Subject: [PATCH 2/9] Add aria-label and loadingInitialValue property to DsDynamicOneboxComponent --- .../models/onebox/dynamic-onebox.component.html | 6 ++++-- .../models/onebox/dynamic-onebox.component.ts | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html index 3c19ecda13f..8681f134339 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/onebox/dynamic-onebox.component.html @@ -21,8 +21,8 @@
- - +