diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html index e6d1a5c80d..21ef4e9de7 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.html +++ b/src/app/+my-dspace-page/my-dspace-page.component.html @@ -19,7 +19,7 @@
{ public getThumbnailFor(item: Item): Observable> { return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe( switchMap((bundleRD: RemoteData) => { - if (hasValue(bundleRD.payload)) { + if (isNotEmpty(bundleRD.payload)) { return this.findAllByBundle(bundleRD.payload, { elementsPerPage: 1 }).pipe( map((bitstreamRD: RemoteData>) => { if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) { @@ -108,7 +108,7 @@ export class BitstreamDataService extends DataService { public getMatchingThumbnail(item: Item, bitstreamInOriginal: Bitstream): Observable> { return this.bundleService.findByItemAndName(item, 'THUMBNAIL').pipe( switchMap((bundleRD: RemoteData) => { - if (hasValue(bundleRD.payload)) { + if (isNotEmpty(bundleRD.payload)) { return this.findAllByBundle(bundleRD.payload, { elementsPerPage: Number.MAX_SAFE_INTEGER }).pipe( map((bitstreamRD: RemoteData>) => { if (hasValue(bitstreamRD.payload) && hasValue(bitstreamRD.payload.page)) { diff --git a/src/app/core/eperson/group-data.service.ts b/src/app/core/eperson/group-data.service.ts index 2beeb588a9..532f42323a 100644 --- a/src/app/core/eperson/group-data.service.ts +++ b/src/app/core/eperson/group-data.service.ts @@ -18,6 +18,8 @@ import { RemoteData } from '../data/remote-data'; import { PaginatedList } from '../data/paginated-list'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; +import { dataService } from '../cache/builders/build-decorators'; +import { GROUP } from './models/group.resource-type'; /** * Provides methods to retrieve eperson group resources. @@ -25,6 +27,7 @@ import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; @Injectable({ providedIn: 'root' }) +@dataService(GROUP) export class GroupDataService extends DataService { protected linkPath = 'groups'; protected browseEndpoint = ''; diff --git a/src/app/core/shared/search/search.service.ts b/src/app/core/shared/search/search.service.ts index 1a016e64f8..06dfd6dba0 100644 --- a/src/app/core/shared/search/search.service.ts +++ b/src/app/core/shared/search/search.service.ts @@ -2,7 +2,7 @@ import { combineLatest as observableCombineLatest, Observable, of as observableO import { Injectable, OnDestroy } from '@angular/core'; import { NavigationExtras, Router } from '@angular/router'; import { first, map, switchMap, tap } from 'rxjs/operators'; -import { followLink } from '../../../shared/utils/follow-link-config.model'; +import { followLink, FollowLinkConfig } from '../../../shared/utils/follow-link-config.model'; import { LinkService } from '../../cache/builders/link.service'; import { FacetConfigSuccessResponse, FacetValueSuccessResponse, SearchSuccessResponse } from '../../cache/response.models'; import { PaginatedList } from '../../data/paginated-list'; @@ -107,10 +107,11 @@ export class SearchService implements OnDestroy { * Method to retrieve a paginated list of search results from the server * @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search * @param responseMsToLive The amount of milliseconds for the response to live in cache + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved * @returns {Observable>>>} Emits a paginated list with all search results found */ - search(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number): Observable>>> { - return this.getPaginatedResults(this.searchEntries(searchOptions)); + search(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number, ...linksToFollow: Array>): Observable>>> { + return this.getPaginatedResults(this.searchEntries(searchOptions), ...linksToFollow); } /** @@ -151,9 +152,10 @@ export class SearchService implements OnDestroy { /** * Method to convert the parsed responses into a paginated list of search results * @param searchEntries: The request entries from the search method + * @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved * @returns {Observable>>>} Emits a paginated list with all search results found */ - getPaginatedResults(searchEntries: Observable<{ searchOptions: PaginatedSearchOptions, requestEntry: RequestEntry }>): Observable>>> { + getPaginatedResults(searchEntries: Observable<{ searchOptions: PaginatedSearchOptions, requestEntry: RequestEntry }>, ...linksToFollow: Array>): Observable>>> { const requestEntryObs: Observable = searchEntries.pipe( map((entry) => entry.requestEntry), ); @@ -174,7 +176,7 @@ export class SearchService implements OnDestroy { }), // Send a request for each item to ensure fresh cache tap((reqs: RestRequest[]) => reqs.forEach((req: RestRequest) => this.requestService.configure(req))), - map((reqs: RestRequest[]) => reqs.map((req: RestRequest) => this.rdb.buildSingle(req.href))), + map((reqs: RestRequest[]) => reqs.map((req: RestRequest) => this.rdb.buildSingle(req.href, ...linksToFollow))), switchMap((input: Array>>) => this.rdb.aggregate(input)), ); diff --git a/src/app/core/tasks/models/claimed-task-object.model.ts b/src/app/core/tasks/models/claimed-task-object.model.ts index 9ec28bc2e0..3ea78595f2 100644 --- a/src/app/core/tasks/models/claimed-task-object.model.ts +++ b/src/app/core/tasks/models/claimed-task-object.model.ts @@ -1,6 +1,5 @@ import { inheritSerialization } from 'cerialize'; -import { typedObject } from '../../cache/builders/build-decorators'; -import { DSpaceObject } from '../../shared/dspace-object.model'; +import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators'; import { CLAIMED_TASK } from './claimed-task-object.resource-type'; import { TaskObject } from './task-object.model'; @@ -8,7 +7,8 @@ import { TaskObject } from './task-object.model'; * A model class for a ClaimedTask. */ @typedObject -@inheritSerialization(DSpaceObject) +@inheritSerialization(TaskObject) +@inheritLinkAnnotations(TaskObject) export class ClaimedTask extends TaskObject { static type = CLAIMED_TASK; } diff --git a/src/app/core/tasks/models/pool-task-object.model.ts b/src/app/core/tasks/models/pool-task-object.model.ts index 04fe572502..501849e8ec 100644 --- a/src/app/core/tasks/models/pool-task-object.model.ts +++ b/src/app/core/tasks/models/pool-task-object.model.ts @@ -1,5 +1,5 @@ import { inheritSerialization } from 'cerialize'; -import { typedObject } from '../../cache/builders/build-decorators'; +import { inheritLinkAnnotations, typedObject } from '../../cache/builders/build-decorators'; import { POOL_TASK } from './pool-task-object.resource-type'; import { TaskObject } from './task-object.model'; @@ -8,6 +8,7 @@ import { TaskObject } from './task-object.model'; */ @typedObject @inheritSerialization(TaskObject) +@inheritLinkAnnotations(TaskObject) export class PoolTask extends TaskObject { static type = POOL_TASK; } diff --git a/src/app/core/tasks/models/task-object.model.ts b/src/app/core/tasks/models/task-object.model.ts index ac659ca9e5..b56cec3a7e 100644 --- a/src/app/core/tasks/models/task-object.model.ts +++ b/src/app/core/tasks/models/task-object.model.ts @@ -12,6 +12,7 @@ import { DSpaceObject } from '../../shared/dspace-object.model'; import { HALLink } from '../../shared/hal-link.model'; import { WorkflowItem } from '../../submission/models/workflowitem.model'; import { TASK_OBJECT } from './task-object.resource-type'; +import { WORKFLOWITEM } from '../../eperson/models/workflowitem.resource-type'; /** * An abstract model class for a TaskObject. @@ -45,7 +46,7 @@ export class TaskObject extends DSpaceObject implements CacheableObject { @deserialize _links: { self: HALLink; - eperson: HALLink; + owner: HALLink; group: HALLink; workflowitem: HALLink; }; @@ -54,7 +55,7 @@ export class TaskObject extends DSpaceObject implements CacheableObject { * The EPerson for this task * Will be undefined unless the eperson {@link HALLink} has been resolved. */ - @link(EPERSON) + @link(EPERSON, false, 'owner') eperson?: Observable>; /** @@ -68,7 +69,7 @@ export class TaskObject extends DSpaceObject implements CacheableObject { * The WorkflowItem for this task * Will be undefined unless the workflowitem {@link HALLink} has been resolved. */ - @link(WorkflowItem.type) + @link(WORKFLOWITEM) workflowitem?: Observable> | WorkflowItem; } diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html index 3a8cb0cded..df8fb0eae7 100644 --- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html +++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.html @@ -2,7 +2,7 @@ {{'submission.workflow.tasks.claimed.edit' | translate}} diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html index d4ecaaa332..a03d8c96fe 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html @@ -1,8 +1,10 @@ - - + + + - + + diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts index 074ce56f92..bdeba1a894 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts @@ -11,6 +11,9 @@ import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspa import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model'; +import { VarDirective } from '../../../utils/var.directive'; +import { getMockLinkService } from '../../../mocks/mock-link-service'; +import { LinkService } from '../../../../core/cache/builders/link.service'; let component: ClaimedTaskSearchResultDetailElementComponent; let fixture: ComponentFixture; @@ -53,12 +56,16 @@ const rdItem = createSuccessfulRemoteDataObject(item); const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdItem) }); const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem); mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); +const linkService = getMockLinkService(); describe('ClaimedTaskSearchResultDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [ClaimedTaskSearchResultDetailElementComponent], + declarations: [ClaimedTaskSearchResultDetailElementComponent, VarDirective], + providers: [ + { provide: LinkService, useValue: linkService } + ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ClaimedTaskSearchResultDetailElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } @@ -75,8 +82,12 @@ describe('ClaimedTaskSearchResultDetailElementComponent', () => { fixture.detectChanges(); }); - it('should init item properly', () => { - expect(component.workflowitem).toEqual(workflowitem); + it('should init workflowitem properly', (done) => { + component.workflowitemRD$.subscribe((workflowitemRD) => { + expect(linkService.resolveLink).toHaveBeenCalled(); + expect(workflowitemRD.payload).toEqual(workflowitem); + done(); + }); }); it('should have properly status', () => { 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 72ffca4b98..f6abb444d5 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 @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; -import { find } from 'rxjs/operators'; import { RemoteData } from '../../../../core/data/remote-data'; import { ViewMode } from '../../../../core/shared/view-mode.model'; -import { isNotUndefined } from '../../../empty.util'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; import { SearchResultDetailElementComponent } from '../search-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model'; +import { followLink } from '../../../utils/follow-link-config.model'; +import { LinkService } from '../../../../core/cache/builders/link.service'; /** * This component renders claimed task object for the search result in the detail view. @@ -38,25 +38,24 @@ export class ClaimedTaskSearchResultDetailElementComponent extends SearchResultD /** * The workflowitem object that belonging to the result object */ - public workflowitem: WorkflowItem; + public workflowitemRD$: Observable>; + + constructor(protected linkService: LinkService) { + super(); + } /** * Initialize all instance variables */ ngOnInit() { super.ngOnInit(); - this.initWorkflowItem(this.dso.workflowitem as Observable>); - } - - /** - * Retrieve workflow item from result object - */ - initWorkflowItem(wfi$: Observable>) { - wfi$.pipe( - find((rd: RemoteData) => (rd.hasSucceeded && isNotUndefined(rd.payload))) - ).subscribe((rd: RemoteData) => { - this.workflowitem = rd.payload; - }); + this.linkService.resolveLink(this.dso, followLink( + 'workflowitem', + null, + followLink('item', null, followLink('bundles')), + followLink('submitter') + )); + this.workflowitemRD$ = this.dso.workflowitem as Observable>; } } 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 ab2c24c435..cbc3f9ccfb 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,9 +10,9 @@
- + - +