From 0d5fc8a1c0035e59b9ed44cbfccc4c6fc66c823f Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Mon, 28 Jun 2021 12:28:59 +0200 Subject: [PATCH 1/7] refactor followlinks to use a single object for all params and add an isOptional param. Also add support for embedding links to search service --- .../bitstream-page.resolver.ts | 2 +- .../collection-page.resolver.ts | 2 +- .../item-authorizations.component.ts | 2 +- .../edit-relationship-list.component.ts | 2 +- src/app/+item-page/item.resolver.ts | 8 +-- src/app/+search-page/search.component.ts | 4 +- .../community-list-service.ts | 8 +-- .../core/cache/builders/link.service.spec.ts | 10 +-- src/app/core/cache/builders/link.service.ts | 9 +-- .../remote-data-build.service.spec.ts | 2 +- .../builders/remote-data-build.service.ts | 2 +- src/app/core/data/data.service.spec.ts | 26 +++++-- .../data/dso-redirect-data.service.spec.ts | 22 +++++- src/app/core/shared/search/search.service.ts | 72 +++++++++++++++++-- .../vocabularies/vocabulary.service.ts | 6 +- ...-search-result-detail-element.component.ts | 4 +- ...-search-result-detail-element.component.ts | 4 +- ...ed-search-result-list-element.component.ts | 5 +- ...ed-search-result-list-element.component.ts | 5 +- ...ed-search-result-list-element.component.ts | 2 +- ...ol-search-result-list-element.component.ts | 2 +- .../shared/utils/follow-link-config.model.ts | 35 ++++++--- 22 files changed, 170 insertions(+), 64 deletions(-) diff --git a/src/app/+bitstream-page/bitstream-page.resolver.ts b/src/app/+bitstream-page/bitstream-page.resolver.ts index a876b22d5e..fd9d5b351b 100644 --- a/src/app/+bitstream-page/bitstream-page.resolver.ts +++ b/src/app/+bitstream-page/bitstream-page.resolver.ts @@ -35,7 +35,7 @@ export class BitstreamPageResolver implements Resolve> { */ get followLinks(): FollowLinkConfig[] { return [ - followLink('bundle', undefined, true, true, true, followLink('item')), + followLink('bundle', {}, followLink('item')), followLink('format') ]; } diff --git a/src/app/+collection-page/collection-page.resolver.ts b/src/app/+collection-page/collection-page.resolver.ts index f6f87f117c..d476a180d3 100644 --- a/src/app/+collection-page/collection-page.resolver.ts +++ b/src/app/+collection-page/collection-page.resolver.ts @@ -14,7 +14,7 @@ import { ResolvedAction } from '../core/resolving/resolver.actions'; * Requesting them as embeds will limit the number of requests */ export const COLLECTION_PAGE_LINKS_TO_FOLLOW: FollowLinkConfig[] = [ - followLink('parentCommunity', undefined, true, true, true, + followLink('parentCommunity', {}, followLink('parentCommunity') ), followLink('logo') diff --git a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index fb193b24d4..e4899abe3a 100644 --- a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -79,7 +79,7 @@ export class ItemAuthorizationsComponent implements OnInit, OnDestroy { getFirstSucceededRemoteDataWithNotEmptyPayload(), map((item: Item) => this.linkService.resolveLink( item, - followLink('bundles', new FindListOptions(), true, true, true, followLink('bitstreams')) + followLink('bundles', {}, followLink('bitstreams')) )) ) as Observable; diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts index 3f9637cdc9..3f1d046a87 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts @@ -323,7 +323,7 @@ export class EditRelationshipListComponent implements OnInit { private getItemRelationships() { this.linkService.resolveLink(this.item, - followLink('relationships', undefined, true, true, true, + followLink('relationships', {}, followLink('relationshipType'), followLink('leftItem'), followLink('rightItem'), diff --git a/src/app/+item-page/item.resolver.ts b/src/app/+item-page/item.resolver.ts index 99b96511fe..217529d271 100644 --- a/src/app/+item-page/item.resolver.ts +++ b/src/app/+item-page/item.resolver.ts @@ -15,13 +15,13 @@ import { ResolvedAction } from '../core/resolving/resolver.actions'; * Requesting them as embeds will limit the number of requests */ export const ITEM_PAGE_LINKS_TO_FOLLOW: FollowLinkConfig[] = [ - followLink('owningCollection', undefined, true, true, true, - followLink('parentCommunity', undefined, true, true, true, + followLink('owningCollection', {}, + followLink('parentCommunity', {}, followLink('parentCommunity')) ), - followLink('bundles', new FindListOptions(), true, true, true, followLink('bitstreams')), + followLink('bundles', {}, followLink('bitstreams')), followLink('relationships'), - followLink('version', undefined, true, true, true, followLink('versionhistory')), + followLink('version', {}, followLink('versionhistory')), ]; /** diff --git a/src/app/+search-page/search.component.ts b/src/app/+search-page/search.component.ts index b817c82a57..f6e9664911 100644 --- a/src/app/+search-page/search.component.ts +++ b/src/app/+search-page/search.component.ts @@ -16,9 +16,11 @@ import { SearchResult } from '../shared/search/search-result.model'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; import { SearchService } from '../core/shared/search/search.service'; import { currentPath } from '../shared/utils/route.utils'; -import { Router} from '@angular/router'; +import { Router } from '@angular/router'; import { Context } from '../core/shared/context.model'; import { SortOptions } from '../core/cache/models/sort-options.model'; +import { followLink } from '../shared/utils/follow-link-config.model'; +import { Item } from '../core/shared/item.model'; @Component({ selector: 'ds-search', diff --git a/src/app/community-list-page/community-list-service.ts b/src/app/community-list-page/community-list-service.ts index cbf70ca39a..e882ae5902 100644 --- a/src/app/community-list-page/community-list-service.ts +++ b/src/app/community-list-page/community-list-service.ts @@ -174,8 +174,8 @@ export class CommunityListService { direction: options.sort.direction } }, - followLink('subcommunities', this.configOnePage, true, true), - followLink('collections', this.configOnePage, true, true)) + followLink('subcommunities', { findListOptions: this.configOnePage }), + followLink('collections', { findListOptions: this.configOnePage })) .pipe( getFirstSucceededRemoteData(), map((results) => results.payload), @@ -242,8 +242,8 @@ export class CommunityListService { elementsPerPage: MAX_COMCOLS_PER_PAGE, currentPage: i }, - followLink('subcommunities', this.configOnePage, true, true), - followLink('collections', this.configOnePage, true, true)) + followLink('subcommunities', { findListOptions: this.configOnePage }), + followLink('collections', { findListOptions: this.configOnePage })) .pipe( getFirstCompletedRemoteData(), switchMap((rd: RemoteData>) => { diff --git a/src/app/core/cache/builders/link.service.spec.ts b/src/app/core/cache/builders/link.service.spec.ts index a6d9c59492..f567c39314 100644 --- a/src/app/core/cache/builders/link.service.spec.ts +++ b/src/app/core/cache/builders/link.service.spec.ts @@ -102,7 +102,7 @@ describe('LinkService', () => { describe('resolveLink', () => { describe(`when the linkdefinition concerns a single object`, () => { beforeEach(() => { - service.resolveLink(testModel, followLink('predecessor', {}, true, true, true, followLink('successor'))); + service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))); }); it('should call dataservice.findByHref with the correct href and nested links', () => { expect(testDataService.findByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, true, true, followLink('successor')); @@ -116,7 +116,7 @@ describe('LinkService', () => { propertyName: 'predecessor', isList: true }); - service.resolveLink(testModel, followLink('predecessor', { some: 'options ' } as any, true, true, true, followLink('successor'))); + service.resolveLink(testModel, followLink('predecessor', { findListOptions: { some: 'options ' } as any }, followLink('successor'))); }); it('should call dataservice.findAllByHref with the correct href, findListOptions, and nested links', () => { expect(testDataService.findAllByHref).toHaveBeenCalledWith(testModel._links.predecessor.href, { some: 'options ' } as any, true, true, followLink('successor')); @@ -124,7 +124,7 @@ describe('LinkService', () => { }); describe('either way', () => { beforeEach(() => { - result = service.resolveLink(testModel, followLink('predecessor', {}, true, true, true, followLink('successor'))); + result = service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))); }); it('should call getLinkDefinition with the correct model and link', () => { @@ -149,7 +149,7 @@ describe('LinkService', () => { }); it('should throw an error', () => { expect(() => { - service.resolveLink(testModel, followLink('predecessor', {}, true, true, true, followLink('successor'))); + service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))); }).toThrow(); }); }); @@ -160,7 +160,7 @@ describe('LinkService', () => { }); it('should throw an error', () => { expect(() => { - service.resolveLink(testModel, followLink('predecessor', {}, true, true, true, followLink('successor'))); + service.resolveLink(testModel, followLink('predecessor', {}, followLink('successor'))); }).toThrow(); }); }); diff --git a/src/app/core/cache/builders/link.service.ts b/src/app/core/cache/builders/link.service.ts index 29f8633da5..66f91dbbd6 100644 --- a/src/app/core/cache/builders/link.service.ts +++ b/src/app/core/cache/builders/link.service.ts @@ -39,7 +39,7 @@ export class LinkService { */ public resolveLinks(model: T, ...linksToFollow: FollowLinkConfig[]): T { linksToFollow.forEach((linkToFollow: FollowLinkConfig) => { - this.resolveLink(model, linkToFollow); + this.resolveLink(model, linkToFollow); }); return model; } @@ -55,9 +55,7 @@ export class LinkService { public resolveLinkWithoutAttaching(model, linkToFollow: FollowLinkConfig): Observable> { const matchingLinkDef = this.getLinkDefinition(model.constructor, linkToFollow.name); - if (hasNoValue(matchingLinkDef)) { - throw new Error(`followLink('${linkToFollow.name}') was used for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${linkToFollow.name}`); - } else { + if (hasValue(matchingLinkDef)) { const provider = this.getDataServiceFor(matchingLinkDef.resourceType); if (hasNoValue(provider)) { @@ -84,7 +82,10 @@ export class LinkService { throw e; } } + } else if (!linkToFollow.isOptional) { + throw new Error(`followLink('${linkToFollow.name}') was used as a required link for a ${model.constructor.name}, but there is no property on ${model.constructor.name} models with an @link() for ${linkToFollow.name}`); } + return EMPTY; } diff --git a/src/app/core/cache/builders/remote-data-build.service.spec.ts b/src/app/core/cache/builders/remote-data-build.service.spec.ts index cb193724a7..0cb45733a6 100644 --- a/src/app/core/cache/builders/remote-data-build.service.spec.ts +++ b/src/app/core/cache/builders/remote-data-build.service.spec.ts @@ -523,7 +523,7 @@ describe('RemoteDataBuildService', () => { let paginatedLinksToFollow; beforeEach(() => { paginatedLinksToFollow = [ - followLink('page', undefined, true, true, true, ...linksToFollow), + followLink('page', {}, ...linksToFollow), ...linksToFollow ]; }); diff --git a/src/app/core/cache/builders/remote-data-build.service.ts b/src/app/core/cache/builders/remote-data-build.service.ts index 11815c133b..6b67549f2d 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -271,7 +271,7 @@ export class RemoteDataBuildService { * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved */ buildList(href$: string | Observable, ...linksToFollow: FollowLinkConfig[]): Observable>> { - return this.buildFromHref>(href$, followLink('page', undefined, false, true, true, ...linksToFollow)); + return this.buildFromHref>(href$, followLink('page', { shouldEmbed: false }, ...linksToFollow)); } /** diff --git a/src/app/core/data/data.service.spec.ts b/src/app/core/data/data.service.spec.ts index 88b15754af..5bc7423824 100644 --- a/src/app/core/data/data.service.spec.ts +++ b/src/app/core/data/data.service.spec.ts @@ -233,7 +233,7 @@ describe('DataService', () => { const config: FindListOptions = Object.assign(new FindListOptions(), { elementsPerPage: 5 }); - (service as any).getFindAllHref({}, null, followLink('bundles', config, true, true, true)).subscribe((value) => { + (service as any).getFindAllHref({}, null, followLink('bundles', { findListOptions: config })).subscribe((value) => { expect(value).toBe(expected); }); }); @@ -253,7 +253,7 @@ describe('DataService', () => { elementsPerPage: 2 }); - (service as any).getFindAllHref({}, null, followLink('bundles'), followLink('owningCollection', config, true, true, true), followLink('templateItemOf')).subscribe((value) => { + (service as any).getFindAllHref({}, null, followLink('bundles'), followLink('owningCollection', { findListOptions: config }), followLink('templateItemOf')).subscribe((value) => { expect(value).toBe(expected); }); }); @@ -261,7 +261,13 @@ describe('DataService', () => { it('should not include linksToFollow with shouldEmbed = false', () => { const expected = `${endpoint}?embed=templateItemOf`; - (service as any).getFindAllHref({}, null, followLink('bundles', undefined, false), followLink('owningCollection', undefined, false), followLink('templateItemOf')).subscribe((value) => { + (service as any).getFindAllHref( + {}, + null, + followLink('bundles', { shouldEmbed: false }), + followLink('owningCollection', { shouldEmbed: false }), + followLink('templateItemOf') + ).subscribe((value) => { expect(value).toBe(expected); }); }); @@ -269,7 +275,7 @@ describe('DataService', () => { it('should include nested linksToFollow 3lvl', () => { const expected = `${endpoint}?embed=owningCollection/itemtemplate/relationships`; - (service as any).getFindAllHref({}, null, followLink('owningCollection', undefined, true, true, true, followLink('itemtemplate', undefined, true, true, true, followLink('relationships')))).subscribe((value) => { + (service as any).getFindAllHref({}, null, followLink('owningCollection', {}, followLink('itemtemplate', {}, followLink('relationships')))).subscribe((value) => { expect(value).toBe(expected); }); }); @@ -279,7 +285,7 @@ describe('DataService', () => { const config: FindListOptions = Object.assign(new FindListOptions(), { elementsPerPage: 4 }); - (service as any).getFindAllHref({}, null, followLink('owningCollection', undefined, true, true, true, followLink('itemtemplate', config, true, true, true))).subscribe((value) => { + (service as any).getFindAllHref({}, null, followLink('owningCollection', {}, followLink('itemtemplate', { findListOptions: config }))).subscribe((value) => { expect(value).toBe(expected); }); }); @@ -308,13 +314,19 @@ describe('DataService', () => { it('should not include linksToFollow with shouldEmbed = false', () => { const expected = `${endpointMock}/${resourceIdMock}?embed=templateItemOf`; - const result = (service as any).getIDHref(endpointMock, resourceIdMock, followLink('bundles', undefined, false), followLink('owningCollection', undefined, false), followLink('templateItemOf')); + const result = (service as any).getIDHref( + endpointMock, + resourceIdMock, + followLink('bundles', { shouldEmbed: false }), + followLink('owningCollection', { shouldEmbed: false }), + followLink('templateItemOf') + ); expect(result).toEqual(expected); }); it('should include nested linksToFollow 3lvl', () => { const expected = `${endpointMock}/${resourceIdMock}?embed=owningCollection/itemtemplate/relationships`; - const result = (service as any).getIDHref(endpointMock, resourceIdMock, followLink('owningCollection', undefined, true, true, true,followLink('itemtemplate', undefined, true, true, true, followLink('relationships')))); + const result = (service as any).getIDHref(endpointMock, resourceIdMock, followLink('owningCollection', {}, followLink('itemtemplate', {}, followLink('relationships')))); expect(result).toEqual(expected); }); }); diff --git a/src/app/core/data/dso-redirect-data.service.spec.ts b/src/app/core/data/dso-redirect-data.service.spec.ts index d64f37ad78..bcd25487c2 100644 --- a/src/app/core/data/dso-redirect-data.service.spec.ts +++ b/src/app/core/data/dso-redirect-data.service.spec.ts @@ -119,7 +119,7 @@ describe('DsoRedirectDataService', () => { }); it('should navigate to entities route with the corresponding entity type', () => { remoteData.payload.type = 'item'; - remoteData.payload.metadata = { + remoteData.payload.metadata = { 'dspace.entity.type': [ { language: 'en_US', @@ -174,13 +174,29 @@ describe('DsoRedirectDataService', () => { it('should not include linksToFollow with shouldEmbed = false', () => { const expected = `${requestUUIDURL}&embed=templateItemOf`; - const result = (service as any).getIDHref(pidLink, dsoUUID, followLink('bundles', undefined, false), followLink('owningCollection', undefined, false), followLink('templateItemOf')); + const result = (service as any).getIDHref( + pidLink, + dsoUUID, + followLink('bundles', { shouldEmbed: false }), + followLink('owningCollection', { shouldEmbed: false }), + followLink('templateItemOf') + ); expect(result).toEqual(expected); }); it('should include nested linksToFollow 3lvl', () => { const expected = `${requestUUIDURL}&embed=owningCollection/itemtemplate/relationships`; - const result = (service as any).getIDHref(pidLink, dsoUUID, followLink('owningCollection', undefined, true, true, true, followLink('itemtemplate', undefined, true, true, true, followLink('relationships')))); + const result = (service as any).getIDHref( + pidLink, + dsoUUID, + followLink('owningCollection', + {}, + followLink('itemtemplate', + {}, + followLink('relationships') + ) + ) + ); expect(result).toEqual(expected); }); }); diff --git a/src/app/core/shared/search/search.service.ts b/src/app/core/shared/search/search.service.ts index 9cb284db32..75723366bc 100644 --- a/src/app/core/shared/search/search.service.ts +++ b/src/app/core/shared/search/search.service.ts @@ -41,6 +41,43 @@ import { SearchConfig } from './search-filters/search-config.model'; import { PaginationService } from '../../pagination/pagination.service'; import { SearchConfigurationService } from './search-configuration.service'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; +import { DataService } from '../../data/data.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../../core.reducers'; +import { ObjectCacheService } from '../../cache/object-cache.service'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { HttpClient } from '@angular/common/http'; +import { DSOChangeAnalyzer } from '../../data/dso-change-analyzer.service'; + +/* tslint:disable:max-classes-per-file */ +/** + * A class that lets us delegate some methods to DataService + */ +class DataServiceImpl extends DataService { + protected linkPath = 'discover'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DSOChangeAnalyzer) { + super(); + } + + /** + * Adds the embed options to the link for the request + * @param href The href the params are to be added to + * @param args params for the query string + * @param linksToFollow links we want to embed in query string if shouldEmbed is true + */ + public addEmbedParams(href: string, args: string[], ...linksToFollow: FollowLinkConfig[]) { + return super.addEmbedParams(href, args, ...linksToFollow); + } +} /** * Service that performs all general actions that have to do with the search page @@ -78,6 +115,11 @@ export class SearchService implements OnDestroy { */ private sub; + /** + * Instance of DataServiceImpl that lets us delegate some methods to DataService + */ + private searchDataService: DataServiceImpl; + constructor(private router: Router, private routeService: RouteService, protected requestService: RequestService, @@ -89,6 +131,16 @@ export class SearchService implements OnDestroy { private paginationService: PaginationService, private searchConfigurationService: SearchConfigurationService ) { + this.searchDataService = new DataServiceImpl( + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined + ); } /** @@ -131,7 +183,17 @@ export class SearchService implements OnDestroy { search(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig[]): Observable>> { const href$ = this.getEndpoint(searchOptions); - href$.pipe(take(1)).subscribe((url: string) => { + href$.pipe( + take(1), + map((href: string) => { + const args = this.searchDataService.addEmbedParams(href, [], ...linksToFollow); + if (isNotEmpty(args)) { + return new URLCombiner(href, `?${args.join('&')}`).toString(); + } else { + return href; + } + }) + ).subscribe((url: string) => { const request = new this.request(this.requestService.generateRequestId(), url); const getResponseParserFn: () => GenericConstructor = () => { @@ -152,7 +214,7 @@ export class SearchService implements OnDestroy { ); return this.directlyAttachIndexableObjects(sqr$, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); - } + } /** * Method to retrieve request entries for search results from the server @@ -399,9 +461,9 @@ export class SearchService implements OnDestroy { let pageParams = { page: 1 }; const queryParams = { view: viewMode }; if (viewMode === ViewMode.DetailedListElement) { - pageParams = Object.assign(pageParams, {pageSize: 1}); + pageParams = Object.assign(pageParams, { pageSize: 1 }); } else if (config.pageSize === 1) { - pageParams = Object.assign(pageParams, {pageSize: 10}); + pageParams = Object.assign(pageParams, { pageSize: 10 }); } this.paginationService.updateRouteWithUrl(this.searchConfigurationService.paginationID, hasValue(searchLinkParts) ? searchLinkParts : [this.getSearchLink()], pageParams, queryParams); }); @@ -413,7 +475,7 @@ export class SearchService implements OnDestroy { * @param {string} configurationName the name of the configuration * @returns {Observable>} The found configuration */ - getSearchConfigurationFor(scope?: string, configurationName?: string ): Observable> { + getSearchConfigurationFor(scope?: string, configurationName?: string): Observable> { const href$ = this.halService.getEndpoint(this.configurationLinkPath).pipe( map((url: string) => this.getConfigUrl(url, scope, configurationName)), ); diff --git a/src/app/core/submission/vocabularies/vocabulary.service.ts b/src/app/core/submission/vocabularies/vocabulary.service.ts index d82ef01087..da58512441 100644 --- a/src/app/core/submission/vocabularies/vocabulary.service.ts +++ b/src/app/core/submission/vocabularies/vocabulary.service.ts @@ -173,7 +173,7 @@ export class VocabularyService { ); // TODO remove false for the entries embed when https://github.com/DSpace/DSpace/issues/3096 is solved - return this.findVocabularyById(vocabularyOptions.name, true, true, followLink('entries', options, false)).pipe( + return this.findVocabularyById(vocabularyOptions.name, true, true, followLink('entries', { findListOptions: options, shouldEmbed: false })).pipe( getFirstSucceededRemoteDataPayload(), switchMap((vocabulary: Vocabulary) => vocabulary.entries), ); @@ -200,7 +200,7 @@ export class VocabularyService { ); // TODO remove false for the entries embed when https://github.com/DSpace/DSpace/issues/3096 is solved - return this.findVocabularyById(vocabularyOptions.name, true, true, followLink('entries', options, false)).pipe( + return this.findVocabularyById(vocabularyOptions.name, true, true, followLink('entries', { findListOptions: options, shouldEmbed: false })).pipe( getFirstSucceededRemoteDataPayload(), switchMap((vocabulary: Vocabulary) => vocabulary.entries), ); @@ -249,7 +249,7 @@ export class VocabularyService { ); // TODO remove false for the entries embed when https://github.com/DSpace/DSpace/issues/3096 is solved - return this.findVocabularyById(vocabularyOptions.name, true, true, followLink('entries', options, false)).pipe( + return this.findVocabularyById(vocabularyOptions.name, true, true, followLink('entries', { findListOptions: options, shouldEmbed: false })).pipe( getFirstSucceededRemoteDataPayload(), switchMap((vocabulary: Vocabulary) => vocabulary.entries), getFirstSucceededRemoteListPayload(), diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts index b729307443..74411d2341 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts @@ -49,8 +49,8 @@ export class ClaimedTaskSearchResultDetailElementComponent extends SearchResultD */ ngOnInit() { super.ngOnInit(); - this.linkService.resolveLinks(this.dso, followLink('workflowitem', null, true, true, true, - followLink('item', null, true, true, true, followLink('bundles')), + this.linkService.resolveLinks(this.dso, followLink('workflowitem', {}, + followLink('item', {}, followLink('bundles')), followLink('submitter') ), followLink('action')); this.workflowitemRD$ = this.dso.workflowitem as Observable>; diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts index a8b2514ffb..df27abd42e 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts @@ -48,8 +48,8 @@ export class PoolSearchResultDetailElementComponent extends SearchResultDetailEl */ ngOnInit() { super.ngOnInit(); - this.linkService.resolveLinks(this.dso, followLink('workflowitem', null, true, true, true, - followLink('item', null, true, true, true, followLink('bundles')), + this.linkService.resolveLinks(this.dso, followLink('workflowitem', {}, + followLink('item', {}, followLink('bundles')), followLink('submitter') ), followLink('action')); this.workflowitemRD$ = this.dso.workflowitem as Observable>; diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-approved-search-result/claimed-approved-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-approved-search-result/claimed-approved-search-result-list-element.component.ts index 5571782ce2..eaf407d787 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-approved-search-result/claimed-approved-search-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-approved-search-result/claimed-approved-search-result-list-element.component.ts @@ -55,10 +55,7 @@ export class ClaimedApprovedSearchResultListElementComponent extends SearchResul super.ngOnInit(); this.linkService.resolveLinks(this.dso, followLink('workflowitem', - null, - true, - false, - true, + { useCachedVersionIfAvailable: false }, followLink('item'), followLink('submitter') ), diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-search-result/claimed-declined-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-search-result/claimed-declined-search-result-list-element.component.ts index 630aa699a7..0b9a925dbf 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-search-result/claimed-declined-search-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-search-result/claimed-declined-search-result-list-element.component.ts @@ -56,10 +56,7 @@ export class ClaimedDeclinedSearchResultListElementComponent extends SearchResul super.ngOnInit(); this.linkService.resolveLinks(this.dso, followLink('workflowitem', - null, - true, - false, - true, + { useCachedVersionIfAvailable: false }, followLink('item'), followLink('submitter') ), diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts index dae3272889..2cf8f9a231 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts @@ -50,7 +50,7 @@ export class ClaimedSearchResultListElementComponent extends SearchResultListEle */ ngOnInit() { super.ngOnInit(); - this.linkService.resolveLinks(this.dso, followLink('workflowitem', null, true, true, true, + this.linkService.resolveLinks(this.dso, followLink('workflowitem', {}, followLink('item'), followLink('submitter') ), followLink('action')); this.workflowitemRD$ = this.dso.workflowitem as Observable>; diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts index fe4fa715ee..e9d64db572 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts @@ -60,7 +60,7 @@ export class PoolSearchResultListElementComponent extends SearchResultListElemen */ ngOnInit() { super.ngOnInit(); - this.linkService.resolveLinks(this.dso, followLink('workflowitem', null, true, true, true, + this.linkService.resolveLinks(this.dso, followLink('workflowitem', {}, followLink('item'), followLink('submitter') ), followLink('action')); this.workflowitemRD$ = this.dso.workflowitem as Observable>; diff --git a/src/app/shared/utils/follow-link-config.model.ts b/src/app/shared/utils/follow-link-config.model.ts index c823d53296..08153e1217 100644 --- a/src/app/shared/utils/follow-link-config.model.ts +++ b/src/app/shared/utils/follow-link-config.model.ts @@ -1,5 +1,6 @@ import { FindListOptions } from '../../core/data/request.models'; import { HALResource } from '../../core/shared/hal-resource.model'; +import { hasValue } from '../empty.util'; /** * A class to send the retrieval of a {@link HALLink} @@ -40,6 +41,12 @@ export class FollowLinkConfig { * Defaults to true */ reRequestOnStale? = true; + + /** + * If this is false an error will be thrown if the link doesn't exist on the model it is used on + * Defaults to false + */ + isOptional? = false; } /** @@ -57,23 +64,35 @@ export class FollowLinkConfig { * no valid cached version. Defaults * @param reRequestOnStale: Whether or not the link should automatically be re-requested after the * response becomes stale + * @param isOptional: Whether or not to fail if the link doesn't exist * @param linksToFollow: a list of {@link FollowLinkConfig}s to * use on the retrieved object. */ export const followLink = ( linkName: keyof R['_links'], - findListOptions?: FindListOptions, - shouldEmbed = true, - useCachedVersionIfAvailable = true, - reRequestOnStale = true, - ...linksToFollow: FollowLinkConfig[] -): FollowLinkConfig => { - return { - name: linkName, + { findListOptions, shouldEmbed, useCachedVersionIfAvailable, reRequestOnStale, + isOptional + }: { + findListOptions?: FindListOptions, + shouldEmbed?: boolean, + useCachedVersionIfAvailable?: boolean, + reRequestOnStale?: boolean, + isOptional?: boolean, + } = {}, + ...linksToFollow: FollowLinkConfig[] +): FollowLinkConfig => { + const followLinkConfig = { + name: linkName, + findListOptions: hasValue(findListOptions) ? findListOptions : new FindListOptions(), + shouldEmbed: hasValue(shouldEmbed) ? shouldEmbed : true, + useCachedVersionIfAvailable: hasValue(useCachedVersionIfAvailable) ? useCachedVersionIfAvailable : true, + reRequestOnStale: hasValue(reRequestOnStale) ? reRequestOnStale : true, + isOptional: hasValue(isOptional) ? isOptional : false, linksToFollow }; + return followLinkConfig; }; From acff2186b47c52445107893fbdfde6707e86878a Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Fri, 25 Jun 2021 17:17:56 +0200 Subject: [PATCH 2/7] 80369: Add thumbnail link to Item & Bitstream models --- src/app/core/shared/bitstream.model.ts | 5 +++-- src/app/core/shared/item.model.ts | 10 ++++++++++ src/app/thumbnail/thumbnail.component.spec.ts | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/app/core/shared/bitstream.model.ts b/src/app/core/shared/bitstream.model.ts index 314818b482..baf2f82635 100644 --- a/src/app/core/shared/bitstream.model.ts +++ b/src/app/core/shared/bitstream.model.ts @@ -43,13 +43,14 @@ export class Bitstream extends DSpaceObject implements HALResource { bundle: HALLink; format: HALLink; content: HALLink; + thumbnail: HALLink; }; /** * The thumbnail for this Bitstream - * Needs to be resolved first, but isn't available as a {@link HALLink} yet - * Use BitstreamDataService.getThumbnailFor(…) for now. + * Will be undefined unless the thumbnail {@link HALLink} has been resolved. */ + @link(BITSTREAM, false, 'thumbnail') thumbnail?: Observable>; /** diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index 53eb5e3ce2..65265e76ad 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -19,6 +19,8 @@ import { ITEM } from './item.resource-type'; import { ChildHALResource } from './child-hal-resource.model'; import { Version } from './version.model'; import { VERSION } from './version.resource-type'; +import { BITSTREAM } from './bitstream.resource-type'; +import { Bitstream } from './bitstream.model'; /** * Class representing a DSpace Item @@ -69,6 +71,7 @@ export class Item extends DSpaceObject implements ChildHALResource { owningCollection: HALLink; templateItemOf: HALLink; version: HALLink; + thumbnail: HALLink; self: HALLink; }; @@ -100,6 +103,13 @@ export class Item extends DSpaceObject implements ChildHALResource { @link(RELATIONSHIP, true) relationships?: Observable>>; + /** + * The thumbnail for this Item + * Will be undefined unless the thumbnail {@link HALLink} has been resolved. + */ + @link(BITSTREAM, false, 'thumbnail') + thumbnail?: Observable>; + /** * Method that returns as which type of object this object should be rendered */ diff --git a/src/app/thumbnail/thumbnail.component.spec.ts b/src/app/thumbnail/thumbnail.component.spec.ts index bc9d159750..eea585f9f8 100644 --- a/src/app/thumbnail/thumbnail.component.spec.ts +++ b/src/app/thumbnail/thumbnail.component.spec.ts @@ -78,6 +78,7 @@ describe('ThumbnailComponent', () => { bundle: { href: 'bundle.url' }, format: { href: 'format.url' }, content: { href: 'content.url' }, + thumbnail: undefined, }; }); @@ -126,6 +127,7 @@ describe('ThumbnailComponent', () => { bundle: { href: 'bundle.url' }, format: { href: 'format.url' }, content: { href: 'content.url' }, + thumbnail: undefined, }; thumbnail = createSuccessfulRemoteDataObject(bitstream); }); From d21d0eae5568eebf3df0f7d8affa37922de7be85 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Fri, 25 Jun 2021 17:18:01 +0200 Subject: [PATCH 3/7] 80369: Add followLinks for thumbnail --- .../file-section/full-file-section.component.ts | 6 ++++-- src/app/+item-page/item.resolver.ts | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts b/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts index 214484120e..e21c1a32eb 100644 --- a/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts +++ b/src/app/+item-page/full/field-components/file-section/full-file-section.component.ts @@ -68,7 +68,8 @@ export class FullFileSectionComponent extends FileSectionComponent implements On {elementsPerPage: options.pageSize, currentPage: options.currentPage}, true, true, - followLink('format') + followLink('format'), + followLink('thumbnail'), )), tap((rd: RemoteData>) => { if (hasValue(rd.errorMessage)) { @@ -85,7 +86,8 @@ export class FullFileSectionComponent extends FileSectionComponent implements On {elementsPerPage: options.pageSize, currentPage: options.currentPage}, true, true, - followLink('format') + followLink('format'), + followLink('thumbnail'), )), tap((rd: RemoteData>) => { if (hasValue(rd.errorMessage)) { diff --git a/src/app/+item-page/item.resolver.ts b/src/app/+item-page/item.resolver.ts index 217529d271..62b778e95c 100644 --- a/src/app/+item-page/item.resolver.ts +++ b/src/app/+item-page/item.resolver.ts @@ -22,6 +22,7 @@ export const ITEM_PAGE_LINKS_TO_FOLLOW: FollowLinkConfig[] = [ followLink('bundles', {}, followLink('bitstreams')), followLink('relationships'), followLink('version', {}, followLink('versionhistory')), + followLink('thumbnail') ]; /** From c1b1cb2a272039c8afc38727f02702b2b841edc5 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Fri, 25 Jun 2021 17:29:18 +0200 Subject: [PATCH 4/7] 80369: Remove deprecated front-end thumbnail methods --- .../publication/publication.component.html | 2 +- .../item-types/shared/item.component.ts | 17 +--- .../untyped-item/untyped-item.component.html | 2 +- src/app/core/data/bitstream-data.service.ts | 86 ------------------- ...-search-result-grid-element.component.html | 4 +- ...-search-result-grid-element.component.html | 4 +- ...-search-result-grid-element.component.html | 4 +- .../journal-issue.component.html | 2 +- .../journal-volume.component.html | 2 +- .../item-pages/journal/journal.component.html | 2 +- ...-search-result-grid-element.component.html | 4 +- ...-search-result-grid-element.component.html | 4 +- ...-search-result-grid-element.component.html | 4 +- .../org-unit/org-unit.component.html | 2 +- .../item-pages/person/person.component.html | 2 +- .../item-pages/project/project.component.html | 2 +- ...ult-list-submission-element.component.html | 2 +- ...esult-list-submission-element.component.ts | 10 --- ...esult-list-submission-element.component.ts | 10 --- .../item-detail-preview.component.html | 2 +- .../item-detail-preview.component.spec.ts | 7 -- .../item-detail-preview.component.ts | 17 +--- ...-search-result-grid-element.component.html | 5 +- .../search-result-grid-element.component.ts | 9 -- 24 files changed, 27 insertions(+), 178 deletions(-) diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.html b/src/app/+item-page/simple/item-types/publication/publication.component.html index a5282bfa7f..9e61f00e48 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.html +++ b/src/app/+item-page/simple/item-types/publication/publication.component.html @@ -10,7 +10,7 @@
- + diff --git a/src/app/+item-page/simple/item-types/shared/item.component.ts b/src/app/+item-page/simple/item-types/shared/item.component.ts index 130f67edc7..7f437acfbb 100644 --- a/src/app/+item-page/simple/item-types/shared/item.component.ts +++ b/src/app/+item-page/simple/item-types/shared/item.component.ts @@ -7,6 +7,7 @@ import { takeUntilCompletedRemoteData } from '../../../../core/shared/operators' import { getItemPageRoute } from '../../../item-page-routing-paths'; import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; import { RemoteData } from '../../../../core/data/remote-data'; +import { Observable } from 'rxjs/internal/Observable'; @Component({ selector: 'ds-item', @@ -18,28 +19,14 @@ import { RemoteData } from '../../../../core/data/remote-data'; export class ItemComponent implements OnInit { @Input() object: Item; - /** - * The Item's thumbnail - */ - thumbnail$: BehaviorSubject>; - /** * Route to the item page */ itemPageRoute: string; - mediaViewer = environment.mediaViewer; - constructor(protected bitstreamDataService: BitstreamDataService) { - } + mediaViewer = environment.mediaViewer; ngOnInit(): void { this.itemPageRoute = getItemPageRoute(this.object); - - this.thumbnail$ = new BehaviorSubject>(undefined); - this.bitstreamDataService.getThumbnailFor(this.object).pipe( - takeUntilCompletedRemoteData(), - ).subscribe((rd: RemoteData) => { - this.thumbnail$.next(rd); - }); } } diff --git a/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html index bacffbf526..b0157dcfee 100644 --- a/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html +++ b/src/app/+item-page/simple/item-types/untyped-item/untyped-item.component.html @@ -10,7 +10,7 @@
- + diff --git a/src/app/core/data/bitstream-data.service.ts b/src/app/core/data/bitstream-data.service.ts index 1a16abc47f..a29854d9b3 100644 --- a/src/app/core/data/bitstream-data.service.ts +++ b/src/app/core/data/bitstream-data.service.ts @@ -75,92 +75,6 @@ export class BitstreamDataService extends DataService { return this.findAllByHref(bundle._links.bitstreams.href, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow); } - /** - * Retrieves the thumbnail for the given item - * @returns {Observable>} the first bitstream in the THUMBNAIL bundle - */ - // TODO should be implemented rest side. {@link Item} should get a thumbnail link - public getThumbnailFor(item: Item): Observable> { - return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe( - switchMap((bundleRD: RemoteData) => { - if (isNotEmpty(bundleRD.payload)) { - return this.findAllByBundle(bundleRD.payload, { elementsPerPage: 1 }).pipe( - map((bitstreamRD: RemoteData>) => { - if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) { - return new RemoteData( - bitstreamRD.timeCompleted, - bitstreamRD.msToLive, - bitstreamRD.lastUpdated, - bitstreamRD.state, - bitstreamRD.errorMessage, - bitstreamRD.payload.page[0], - bitstreamRD.statusCode - ); - } else { - return bitstreamRD as any; - } - }) - ); - } else { - return [bundleRD as any]; - } - }) - ); - } - - /** - * Retrieve the matching thumbnail for a {@link Bitstream}. - * - * The {@link Item} is technically redundant, but is available - * in all current use cases, and having it simplifies this method - * - * @param item The {@link Item} the {@link Bitstream} and its thumbnail are a part of - * @param bitstreamInOriginal The original {@link Bitstream} to find the thumbnail for - */ - // TODO should be implemented rest side - public getMatchingThumbnail(item: Item, bitstreamInOriginal: Bitstream): Observable> { - return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe( - switchMap((bundleRD: RemoteData) => { - if (isNotEmpty(bundleRD.payload)) { - return this.findAllByBundle(bundleRD.payload, { elementsPerPage: 9999 }).pipe( - map((bitstreamRD: RemoteData>) => { - if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) { - const matchingThumbnail = bitstreamRD.payload.page.find((thumbnail: Bitstream) => - thumbnail.name.startsWith(bitstreamInOriginal.name) - ); - if (hasValue(matchingThumbnail)) { - return new RemoteData( - bitstreamRD.timeCompleted, - bitstreamRD.msToLive, - bitstreamRD.lastUpdated, - bitstreamRD.state, - bitstreamRD.errorMessage, - matchingThumbnail, - bitstreamRD.statusCode - ); - } else { - return new RemoteData( - bitstreamRD.timeCompleted, - bitstreamRD.msToLive, - bitstreamRD.lastUpdated, - RequestEntryState.Error, - 'No matching thumbnail found', - undefined, - 404 - ); - } - } else { - return bitstreamRD as any; - } - }) - ); - } else { - return [bundleRD as any]; - } - }) - ); - } - /** * Retrieve all {@link Bitstream}s in a certain {@link Bundle}. * diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html index feb282d3a7..028876b3d0 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html @@ -8,13 +8,13 @@ rel="noopener noreferrer" [routerLink]="[itemPageRoute]" class="card-img-top full-width">
- +
- +
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html index aa2352b284..65ff75a731 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html @@ -8,13 +8,13 @@ rel="noopener noreferrer" [routerLink]="[itemPageRoute]" class="card-img-top full-width">
- +
- +
diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html index 8fdad59827..0c5824c6d6 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html @@ -8,13 +8,13 @@ rel="noopener noreferrer" [routerLink]="[itemPageRoute]" class="card-img-top full-width">
- +
- +
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html index 8e357140d8..5847be7dd2 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html +++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html @@ -9,7 +9,7 @@
- +
- +
- +
- +
- +
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html index 23de8b134f..680a9909bc 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html @@ -8,13 +8,13 @@ rel="noopener noreferrer" [routerLink]="[itemPageRoute]" class="card-img-top full-width">
- +
- +
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html index 88498a4d67..204f8fc8cb 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html @@ -8,13 +8,13 @@ rel="noopener noreferrer" [routerLink]="[itemPageRoute]" class="card-img-top full-width">
- +
- +
diff --git a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html index d328e93b15..c9ea8fb549 100644 --- a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html +++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html @@ -9,7 +9,7 @@
-
- diff --git a/src/app/entity-groups/research-entities/item-pages/project/project.component.html b/src/app/entity-groups/research-entities/item-pages/project/project.component.html index 181a8dc44e..8f2ff6adcd 100644 --- a/src/app/entity-groups/research-entities/item-pages/project/project.component.html +++ b/src/app/entity-groups/research-entities/item-pages/project/project.component.html @@ -10,7 +10,7 @@
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html index 063e1393cc..13787bb925 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.html @@ -1,6 +1,6 @@
- +
{ - return this.bitstreamDataService.getThumbnailFor(this.dso).pipe( - getFirstSucceededRemoteDataPayload() - ); - } } diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts index 64cf73cfb9..13de40e015 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts @@ -1,8 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; -import { Bitstream } from '../../../../../core/shared/bitstream.model'; -import { getFirstSucceededRemoteDataPayload } from '../../../../../core/shared/operators'; import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; @@ -108,11 +105,4 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu modalComp.value = value; return modalRef.result; } - - // TODO refactor to return RemoteData, and thumbnail template to deal with loading - getThumbnail(): Observable { - return this.bitstreamDataService.getThumbnailFor(this.dso).pipe( - getFirstSucceededRemoteDataPayload() - ); - } } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html index e4d2526eb2..61e2955deb 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.html @@ -10,7 +10,7 @@
- + diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts index 2b38b58598..07acf3ea75 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.spec.ts @@ -126,13 +126,6 @@ describe('ItemDetailPreviewComponent', () => { })); - it('should get item thumbnail', (done) => { - component.getThumbnail().subscribe((thumbnail) => { - expect(thumbnail).toBeDefined(); - done(); - }); - }); - it('should get item bitstreams', (done) => { component.getFiles().subscribe((bitstreams) => { expect(bitstreams).toBeDefined(); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts index a4dc0a1d3d..92c1afcb59 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts @@ -5,10 +5,7 @@ import { first } from 'rxjs/operators'; import { BitstreamDataService } from '../../../../core/data/bitstream-data.service'; import { Item } from '../../../../core/shared/item.model'; -import { - getFirstSucceededRemoteDataPayload, - getFirstSucceededRemoteListPayload -} from '../../../../core/shared/operators'; +import { getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { fadeInOut } from '../../../animations/fade'; import { Bitstream } from '../../../../core/shared/bitstream.model'; @@ -57,11 +54,6 @@ export class ItemDetailPreviewComponent { */ public separator = ', '; - /** - * The item's thumbnail - */ - public thumbnail$: Observable; - /** * Initialize instance variables * @@ -86,13 +78,6 @@ export class ItemDetailPreviewComponent { }); } - // TODO refactor this method to return RemoteData, and the template to deal with loading and errors - public getThumbnail(): Observable { - return this.bitstreamDataService.getThumbnailFor(this.item).pipe( - getFirstSucceededRemoteDataPayload() - ); - } - // TODO refactor this method to return RemoteData, and the template to deal with loading and errors public getFiles(): Observable { return this.bitstreamDataService diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html index bc16853721..d2454b28e6 100644 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.html @@ -6,13 +6,13 @@
- +
- +
@@ -43,4 +43,3 @@
- diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts index 7436d2922e..da1f0ea11b 100644 --- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts @@ -3,13 +3,11 @@ import { Observable } from 'rxjs'; import { SearchResult } from '../../search/search-result.model'; import { BitstreamDataService } from '../../../core/data/bitstream-data.service'; -import { Bitstream } from '../../../core/shared/bitstream.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { Metadata } from '../../../core/shared/metadata.utils'; import { hasValue } from '../../empty.util'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; import { TruncatableService } from '../../truncatable/truncatable.service'; -import { getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators'; @Component({ selector: 'ds-search-result-grid-element', @@ -66,11 +64,4 @@ export class SearchResultGridElementComponent, K exten private isCollapsed(): Observable { return this.truncatableService.isCollapsed(this.dso.id); } - - // TODO refactor to return RemoteData, and thumbnail template to deal with loading - getThumbnail(): Observable { - return this.bitstreamDataService.getThumbnailFor(this.dso as any).pipe( - getFirstSucceededRemoteDataPayload() - ); - } } From eb0b3ae5f45abf6f1472ede711cf1967c668e0d1 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Mon, 28 Jun 2021 12:51:57 +0200 Subject: [PATCH 5/7] 80369: Add optional thumbnail followLink in SearchComponent --- src/app/+search-page/search.component.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/+search-page/search.component.ts b/src/app/+search-page/search.component.ts index f6e9664911..c1caf27b9a 100644 --- a/src/app/+search-page/search.component.ts +++ b/src/app/+search-page/search.component.ts @@ -130,8 +130,11 @@ export class SearchComponent implements OnInit { this.searchLink = this.getSearchLink(); this.searchOptions$ = this.getSearchOptions(); this.sub = this.searchOptions$.pipe( - switchMap((options) => this.service.search(options).pipe(getFirstSucceededRemoteData(), startWith(undefined)))) - .subscribe((results) => { + switchMap((options) => this.service.search( + options, undefined, true, true, followLink('thumbnail', { isOptional: true }) + ).pipe(getFirstSucceededRemoteData(), startWith(undefined)) + ) + ).subscribe((results) => { this.resultsRD$.next(results); }); this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( From abf6d26641993b619c26972e7b4401239667c2ee Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Tue, 29 Jun 2021 17:34:00 +0200 Subject: [PATCH 6/7] 80369: Remove unneeded bundles followLink --- src/app/+item-page/item.resolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/+item-page/item.resolver.ts b/src/app/+item-page/item.resolver.ts index 62b778e95c..b34bb78f39 100644 --- a/src/app/+item-page/item.resolver.ts +++ b/src/app/+item-page/item.resolver.ts @@ -19,7 +19,6 @@ export const ITEM_PAGE_LINKS_TO_FOLLOW: FollowLinkConfig[] = [ followLink('parentCommunity', {}, followLink('parentCommunity')) ), - followLink('bundles', {}, followLink('bitstreams')), followLink('relationships'), followLink('version', {}, followLink('versionhistory')), followLink('thumbnail') From fedf6aa847565fda63be7c7fe8161c908b700713 Mon Sep 17 00:00:00 2001 From: Yura Bondarenko Date: Tue, 29 Jun 2021 21:18:06 +0200 Subject: [PATCH 7/7] 80369: Fix unused imports --- .../item-authorizations/item-authorizations.component.ts | 6 ++---- src/app/+item-page/item.resolver.ts | 1 - .../+item-page/simple/item-types/shared/item.component.ts | 6 ------ src/app/core/data/bitstream-data.service.ts | 5 ++--- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts index e4899abe3a..76597a135b 100644 --- a/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts +++ b/src/app/+item-page/edit-item-page/item-authorizations/item-authorizations.component.ts @@ -4,10 +4,9 @@ import { ActivatedRoute } from '@angular/router'; import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs'; import { catchError, filter, first, map, mergeMap, take } from 'rxjs/operators'; -import { PaginatedList, buildPaginatedList } from '../../../core/data/paginated-list.model'; +import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model'; import { - getFirstSucceededRemoteDataPayload, - getFirstSucceededRemoteDataWithNotEmptyPayload + getFirstSucceededRemoteDataPayload, getFirstSucceededRemoteDataWithNotEmptyPayload, } from '../../../core/shared/operators'; import { Item } from '../../../core/shared/item.model'; import { followLink } from '../../../shared/utils/follow-link-config.model'; @@ -15,7 +14,6 @@ import { LinkService } from '../../../core/cache/builders/link.service'; import { Bundle } from '../../../core/shared/bundle.model'; import { hasValue, isNotEmpty } from '../../../shared/empty.util'; import { Bitstream } from '../../../core/shared/bitstream.model'; -import { FindListOptions } from '../../../core/data/request.models'; /** * Interface for a bundle's bitstream map entry diff --git a/src/app/+item-page/item.resolver.ts b/src/app/+item-page/item.resolver.ts index b34bb78f39..ca6a6c5958 100644 --- a/src/app/+item-page/item.resolver.ts +++ b/src/app/+item-page/item.resolver.ts @@ -5,7 +5,6 @@ import { RemoteData } from '../core/data/remote-data'; import { ItemDataService } from '../core/data/item-data.service'; import { Item } from '../core/shared/item.model'; import { followLink, FollowLinkConfig } from '../shared/utils/follow-link-config.model'; -import { FindListOptions } from '../core/data/request.models'; import { getFirstCompletedRemoteData } from '../core/shared/operators'; import { Store } from '@ngrx/store'; import { ResolvedAction } from '../core/resolving/resolver.actions'; diff --git a/src/app/+item-page/simple/item-types/shared/item.component.ts b/src/app/+item-page/simple/item-types/shared/item.component.ts index 7f437acfbb..793af180c9 100644 --- a/src/app/+item-page/simple/item-types/shared/item.component.ts +++ b/src/app/+item-page/simple/item-types/shared/item.component.ts @@ -1,13 +1,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { environment } from '../../../../../environments/environment'; -import { BitstreamDataService } from '../../../../core/data/bitstream-data.service'; -import { Bitstream } from '../../../../core/shared/bitstream.model'; import { Item } from '../../../../core/shared/item.model'; -import { takeUntilCompletedRemoteData } from '../../../../core/shared/operators'; import { getItemPageRoute } from '../../../item-page-routing-paths'; -import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { Observable } from 'rxjs/internal/Observable'; @Component({ selector: 'ds-item', diff --git a/src/app/core/data/bitstream-data.service.ts b/src/app/core/data/bitstream-data.service.ts index a29854d9b3..3890f4e663 100644 --- a/src/app/core/data/bitstream-data.service.ts +++ b/src/app/core/data/bitstream-data.service.ts @@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { map, switchMap, take } from 'rxjs/operators'; -import { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { hasValue } from '../../shared/empty.util'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; import { dataService } from '../cache/builders/build-decorators'; @@ -18,7 +18,7 @@ import { Item } from '../shared/item.model'; import { BundleDataService } from './bundle-data.service'; import { DataService } from './data.service'; import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; -import { PaginatedList, buildPaginatedList } from './paginated-list.model'; +import { buildPaginatedList, PaginatedList } from './paginated-list.model'; import { RemoteData } from './remote-data'; import { FindListOptions, PutRequest } from './request.models'; import { RequestService } from './request.service'; @@ -28,7 +28,6 @@ import { HttpOptions } from '../dspace-rest/dspace-rest.service'; import { sendRequest } from '../shared/operators'; import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils'; import { PageInfo } from '../shared/page-info.model'; -import { RequestEntryState } from './request.reducer'; /** * A service to retrieve {@link Bitstream}s from the REST API