From b2f966eb832fbcd30e1600466a6192c322fdde95 Mon Sep 17 00:00:00 2001 From: Art Lowel Date: Thu, 23 Jan 2020 14:24:13 +0100 Subject: [PATCH] fix links for relationships --- .../shared/item-relationships-utils.ts | 2 +- src/app/core/cache/builders/link.service.ts | 6 +++++ .../builders/remote-data-build.service.ts | 4 +--- .../config/config-response-parsing.service.ts | 1 + .../data/base-response-parsing.service.ts | 13 ++++++++++- .../core/data/dspace-object-data.service.ts | 1 - src/app/core/data/relationship.service.ts | 23 ++++++++++--------- .../item-relationships/relationship.model.ts | 2 +- src/app/core/shared/item.model.ts | 8 +++---- ...resource-type.ts => item.resource-type.ts} | 0 .../core/shared/relationship.resource-type.ts | 1 - .../submission-response-parsing.service.ts | 1 + ...ynamic-form-control-container.component.ts | 8 +++++-- .../objects/submission-objects.effects.ts | 8 ++++--- 14 files changed, 50 insertions(+), 28 deletions(-) rename src/app/core/shared/{item-resource-type.ts => item.resource-type.ts} (100%) diff --git a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts index 7baf260c61..6b059e8625 100644 --- a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts +++ b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts @@ -74,7 +74,7 @@ export const paginatedRelationsToItems = (thisId: string) => source.pipe( getSucceededRemoteData(), switchMap((relationshipsRD: RemoteData>) => { - return observableZip( + return observableCombineLatest( ...relationshipsRD.payload.page.map((rel: Relationship) => observableCombineLatest(rel.leftItem, rel.rightItem)) ).pipe( map((arr) => diff --git a/src/app/core/cache/builders/link.service.ts b/src/app/core/cache/builders/link.service.ts index ea01ac6d3f..3ba57d8304 100644 --- a/src/app/core/cache/builders/link.service.ts +++ b/src/app/core/cache/builders/link.service.ts @@ -15,6 +15,12 @@ export class LinkService { ) { } + public resolveLinks(model: T, ...linksToFollow: Array>) { + linksToFollow.forEach((linkToFollow: FollowLinkConfig) => { + this.resolveLink(model, linkToFollow); + }); + } + public resolveLink(model, linkToFollow: FollowLinkConfig) { const matchingLinkDef = getLinkDefinition(model.constructor, linkToFollow.name); 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 1664d6817e..a480380fbd 100644 --- a/src/app/core/cache/builders/remote-data-build.service.ts +++ b/src/app/core/cache/builders/remote-data-build.service.ts @@ -227,9 +227,7 @@ export class RemoteDataBuildService { const domainModelConstructor = getMapsTo(normalized.constructor); const domainModel = Object.assign(new domainModelConstructor(), normalized, halLinks); - linksToFollow.forEach((linkToFollow: FollowLinkConfig) => { - this.linkService.resolveLink(domainModel, linkToFollow); - }); + this.linkService.resolveLinks(domainModel, ...linksToFollow); return domainModel; } diff --git a/src/app/core/config/config-response-parsing.service.ts b/src/app/core/config/config-response-parsing.service.ts index d1f49710d3..d674445d54 100644 --- a/src/app/core/config/config-response-parsing.service.ts +++ b/src/app/core/config/config-response-parsing.service.ts @@ -15,6 +15,7 @@ import { ObjectCacheService } from '../cache/object-cache.service'; @Injectable() export class ConfigResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { protected toCache = false; + protected shouldDirectlyAttachEmbeds = true; constructor( @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts index 29c4d872a5..61d966c761 100644 --- a/src/app/core/data/base-response-parsing.service.ts +++ b/src/app/core/data/base-response-parsing.service.ts @@ -16,6 +16,7 @@ export abstract class BaseResponseParsingService { protected abstract EnvConfig: GlobalConfig; protected abstract objectCache: ObjectCacheService; protected abstract toCache: boolean; + protected shouldDirectlyAttachEmbeds = false; protected process(data: any, request: RestRequest): any { if (isNotEmpty(data)) { @@ -32,7 +33,17 @@ export abstract class BaseResponseParsingService { .keys(data._embedded) .filter((property) => data._embedded.hasOwnProperty(property)) .forEach((property) => { - this.process(data._embedded[property], request); + const parsedObj = this.process(data._embedded[property], request); + if (this.shouldDirectlyAttachEmbeds && isNotEmpty(parsedObj)) { + if (isRestPaginatedList(data._embedded[property])) { + object[property] = parsedObj; + object[property].page = parsedObj.page.map((obj) => this.retrieveObjectOrUrl(obj)); + } else if (isRestDataObject(data._embedded[property])) { + object[property] = this.retrieveObjectOrUrl(parsedObj); + } else if (Array.isArray(parsedObj)) { + object[property] = parsedObj.map((obj) => this.retrieveObjectOrUrl(obj)) + } + } }); } diff --git a/src/app/core/data/dspace-object-data.service.ts b/src/app/core/data/dspace-object-data.service.ts index dce218ad13..f9bba19cec 100644 --- a/src/app/core/data/dspace-object-data.service.ts +++ b/src/app/core/data/dspace-object-data.service.ts @@ -9,7 +9,6 @@ import { HALEndpointService } from '../shared/hal-endpoint.service'; import { DataService } from './data.service'; import { RemoteData } from './remote-data'; import { RequestService } from './request.service'; -import { FindListOptions } from './request.models'; import { ObjectCacheService } from '../cache/object-cache.service'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { HttpClient } from '@angular/common/http'; diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index 341a229cfb..0de6954edd 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -1,6 +1,6 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { followLink } from '../../shared/utils/follow-link-config.model'; +import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model'; import { dataService } from '../cache/builders/build-decorators'; import { MemoizedSelector, select, Store } from '@ngrx/store'; import { combineLatest, combineLatest as observableCombineLatest } from 'rxjs'; @@ -167,8 +167,8 @@ export class RelationshipService extends DataService { * Get an item's relationships in the form of an array * @param item */ - getItemRelationshipsArray(item: Item): Observable { - return this.findAllByHref(item._links.relationships.href).pipe( + getItemRelationshipsArray(item: Item, ...linksToFollow: Array>): Observable { + return this.findAllByHref(item._links.relationships.href, undefined, ...linksToFollow).pipe( getSucceededRemoteData(), getRemoteDataPayload(), map((rels: PaginatedList) => rels.page), @@ -183,7 +183,7 @@ export class RelationshipService extends DataService { * @param item */ getRelationshipTypeLabelsByItem(item: Item): Observable { - return this.getItemRelationshipsArray(item).pipe( + return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe( switchMap((relationships: Relationship[]) => observableCombineLatest(relationships.map((relationship: Relationship) => this.getRelationshipTypeLabelByRelationshipAndItem(relationship, item)))), map((labels: string[]) => Array.from(new Set(labels))) ); @@ -212,7 +212,7 @@ export class RelationshipService extends DataService { * @param item */ getRelatedItems(item: Item): Observable { - return this.getItemRelationshipsArray(item).pipe( + return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe( relationsToItems(item.uuid) ); } @@ -225,17 +225,18 @@ export class RelationshipService extends DataService { * @param options */ getRelatedItemsByLabel(item: Item, label: string, options?: FindListOptions): Observable>> { - return this.getItemRelationshipsByLabel(item, label, options).pipe(paginatedRelationsToItems(item.uuid)); + return this.getItemRelationshipsByLabel(item, label, options, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')).pipe(paginatedRelationsToItems(item.uuid)); } /** - * Resolve a given item's relationships into related items, filtered by a relationship label - * and return the items as an array + * Resolve a given item's relationships by label + * This should move to the REST API. + * * @param item * @param label * @param options */ - getItemRelationshipsByLabel(item: Item, label: string, options?: FindListOptions): Observable>> { + getItemRelationshipsByLabel(item: Item, label: string, options?: FindListOptions, ...linksToFollow: Array>): Observable>> { let findListOptions = new FindListOptions(); if (options) { findListOptions = Object.assign(new FindListOptions(), options); @@ -246,7 +247,7 @@ export class RelationshipService extends DataService { } else { findListOptions.searchParams = searchParams; } - return this.searchBy('byLabel', findListOptions, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')); + return this.searchBy('byLabel', findListOptions, ...linksToFollow); } /** @@ -256,7 +257,7 @@ export class RelationshipService extends DataService { * @param uuids */ getRelationshipsByRelatedItemIds(item: Item, uuids: string[]): Observable { - return this.getItemRelationshipsArray(item).pipe( + return this.getItemRelationshipsArray(item, followLink('leftItem'), followLink('rightItem')).pipe( switchMap((relationships: Relationship[]) => { return observableCombineLatest(...relationships.map((relationship: Relationship) => { const isLeftItem$ = this.isItemInUUIDArray(relationship.leftItem, uuids); diff --git a/src/app/core/shared/item-relationships/relationship.model.ts b/src/app/core/shared/item-relationships/relationship.model.ts index 4c6cda84fd..f79329a201 100644 --- a/src/app/core/shared/item-relationships/relationship.model.ts +++ b/src/app/core/shared/item-relationships/relationship.model.ts @@ -5,7 +5,7 @@ import { RemoteData } from '../../data/remote-data'; import { HALLink } from '../hal-link.model'; import { RelationshipType } from './relationship-type.model'; import { Item } from '../item.model'; -import { ITEM } from "../item-resource-type"; +import { ITEM } from "../item.resource-type"; import { RELATIONSHIP } from "../relationship.resource-type"; /** diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index 6a4431a9ad..26cdfd5c7a 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -12,7 +12,7 @@ import { DSpaceObject } from './dspace-object.model'; import { GenericConstructor } from './generic-constructor'; import { HALLink } from './hal-link.model'; import { Relationship } from './item-relationships/relationship.model'; -import { ITEM } from "./item-resource-type"; +import { ITEM } from "./item.resource-type"; import { RELATIONSHIP } from "./relationship.resource-type"; /** @@ -50,13 +50,13 @@ export class Item extends DSpaceObject { * The Collection that owns this Item */ @link(Collection.type) - owningCollection: Observable>; + owningCollection?: Observable>; @link(Bundle.type, true) - bundles: Observable>>; + bundles?: Observable>>; @link(RELATIONSHIP) - relationships: Observable>>; + relationships?: Observable>>; _links: { mappedCollections: HALLink; diff --git a/src/app/core/shared/item-resource-type.ts b/src/app/core/shared/item.resource-type.ts similarity index 100% rename from src/app/core/shared/item-resource-type.ts rename to src/app/core/shared/item.resource-type.ts diff --git a/src/app/core/shared/relationship.resource-type.ts b/src/app/core/shared/relationship.resource-type.ts index afc5526268..c33852be73 100644 --- a/src/app/core/shared/relationship.resource-type.ts +++ b/src/app/core/shared/relationship.resource-type.ts @@ -7,4 +7,3 @@ import { ResourceType } from "./resource-type"; * dependencies in webpack. */ export const RELATIONSHIP = new ResourceType('relationship'); - diff --git a/src/app/core/submission/submission-response-parsing.service.ts b/src/app/core/submission/submission-response-parsing.service.ts index 8bc2971922..dfb0d2af5f 100644 --- a/src/app/core/submission/submission-response-parsing.service.ts +++ b/src/app/core/submission/submission-response-parsing.service.ts @@ -76,6 +76,7 @@ export function normalizeSectionData(obj: any, objIndex?: number) { export class SubmissionResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { protected toCache = false; + protected shouldDirectlyAttachEmbeds = true; constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, protected objectCache: ObjectCacheService, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index 466ad8ac2a..c6fc437a13 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -50,6 +50,7 @@ import { DynamicNGBootstrapTimePickerComponent } from '@ng-dynamic-forms/ui-ng-bootstrap'; import { TranslateService } from '@ngx-translate/core'; +import { followLink } from '../../../utils/follow-link-config.model'; import { Reorderable, ReorderableRelationship @@ -251,7 +252,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo this.subs.push(item$.subscribe((item) => this.item = item)); this.subs.push(collection$.subscribe((collection) => this.collection = collection)); this.reorderables$ = item$.pipe( - switchMap((item) => this.relationService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType) + switchMap((item) => this.relationService.getItemRelationshipsByLabel(item, this.model.relationship.relationshipType, undefined, followLink('leftItem'), followLink('rightItem'), followLink('relationshipType')) .pipe( getAllSucceededRemoteData(), getRemoteDataPayload(), @@ -285,7 +286,10 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo this.relationService.getRelatedItemsByLabel(this.item, this.model.relationship.relationshipType).pipe( map((items: RemoteData>) => items.payload.page.map((item) => Object.assign(new ItemSearchResult(), { indexableObject: item }))), - ).subscribe((relatedItems: Array>) => this.selectableListService.select(this.listId, relatedItems)); + ).subscribe((relatedItems: Array>) => { + console.log('relatedItems', relatedItems); + this.selectableListService.select(this.listId, relatedItems) + }); } } diff --git a/src/app/submission/objects/submission-objects.effects.ts b/src/app/submission/objects/submission-objects.effects.ts index 349cb00d3a..17b59fa08b 100644 --- a/src/app/submission/objects/submission-objects.effects.ts +++ b/src/app/submission/objects/submission-objects.effects.ts @@ -5,6 +5,7 @@ import { from as observableFrom, of as observableOf } from 'rxjs'; import { catchError, map, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { union } from 'lodash'; +import { NormalizedSubmissionSectionModel } from '../../core/config/models/normalized-config-submission-section.model'; import { CompleteInitSubmissionFormAction, @@ -56,9 +57,10 @@ export class SubmissionObjectEffects { map((action: InitSubmissionFormAction) => { const definition = action.payload.submissionDefinition; const mappedActions = []; - definition.sections.page.forEach((sectionDefinition: SubmissionSectionModel) => { - const sectionId = sectionDefinition._links.self.href.substr(sectionDefinition._links.self.href.lastIndexOf('/') + 1); - const config = sectionDefinition._links.config.href || ''; + definition.sections.page.forEach((sectionDefinition: any) => { + const selfLink = sectionDefinition._links.self.href || sectionDefinition._links.self; + const sectionId = selfLink.substr(selfLink.lastIndexOf('/') + 1); + const config = sectionDefinition._links.config ? (sectionDefinition._links.config.href || sectionDefinition._links.config) : ''; const enabled = (sectionDefinition.mandatory) || (isNotEmpty(action.payload.sections) && action.payload.sections.hasOwnProperty(sectionId)); const sectionData = (isNotUndefined(action.payload.sections) && isNotUndefined(action.payload.sections[sectionId])) ? action.payload.sections[sectionId] : Object.create(null); const sectionErrors = null;