diff --git a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts index 2b50b75a2a..a251142755 100644 --- a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.spec.ts @@ -213,9 +213,9 @@ describe('ItemMetadataComponent', () => { }); it('it should call reinstateFieldUpdates on the objectUpdatesService with the correct url and metadata', () => { - expect(objectUpdatesService.getUpdatedFields).toHaveBeenCalledWith(url, comp.item.metadataAsList); - expect(itemService.update).toHaveBeenCalledWith(Object.assign(comp.item, { metadata: Metadata.toMetadataMap(comp.item.metadataAsList) })); - expect(objectUpdatesService.getFieldUpdates).toHaveBeenCalledWith(url, comp.item.metadataAsList); + expect(objectUpdatesService.getUpdatedFields).toHaveBeenCalledWith(url, comp.itemRD$.metadataAsList); + expect(itemService.update).toHaveBeenCalledWith(Object.assign(comp.itemRD$, { metadata: Metadata.toMetadataMap(comp.itemRD$.metadataAsList) })); + expect(objectUpdatesService.getFieldUpdates).toHaveBeenCalledWith(url, comp.itemRD$.metadataAsList); }); }); diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts index bd5f5f2e5c..6016f54445 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts @@ -118,7 +118,7 @@ describe('EditRelationshipListComponent', () => { fixture = TestBed.createComponent(EditRelationshipListComponent); comp = fixture.componentInstance; de = fixture.debugElement; - comp.item = item; + comp.itemRD$ = item; comp.url = url; comp.relationshipLabel = relationshipType.leftLabel; fixture.detectChanges(); diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts index fc6c999a1c..e60a7f3a35 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts @@ -114,7 +114,7 @@ describe('EditRelationshipComponent', () => { comp.url = url; comp.fieldUpdate = fieldUpdate1; - comp.item = item; + comp.itemRD$ = item; fixture.detectChanges(); }); diff --git a/src/app/+item-page/edit-item-page/modify-item-overview/modify-item-overview.component.spec.ts b/src/app/+item-page/edit-item-page/modify-item-overview/modify-item-overview.component.spec.ts index 07ad9a347c..ad5318757b 100644 --- a/src/app/+item-page/edit-item-page/modify-item-overview/modify-item-overview.component.spec.ts +++ b/src/app/+item-page/edit-item-page/modify-item-overview/modify-item-overview.component.spec.ts @@ -32,7 +32,7 @@ describe('ModifyItemOverviewComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(ModifyItemOverviewComponent); comp = fixture.componentInstance; - comp.item = mockItem; + comp.itemRD$ = mockItem; fixture.detectChanges(); }); diff --git a/src/app/+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component.spec.ts index 9461ee0950..ae73881bce 100644 --- a/src/app/+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component.spec.ts @@ -31,7 +31,7 @@ describe('ItemPageAbstractFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemPageAbstractFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(mockField, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(mockField, mockValue); fixture.detectChanges(); })); diff --git a/src/app/+item-page/simple/field-components/specific-field/author/item-page-author-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/author/item-page-author-field.component.spec.ts index d865caff8a..0e439a191b 100644 --- a/src/app/+item-page/simple/field-components/specific-field/author/item-page-author-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/author/item-page-author-field.component.spec.ts @@ -32,7 +32,7 @@ describe('ItemPageAuthorFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemPageAuthorFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(field, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(field, mockValue); fixture.detectChanges(); })); diff --git a/src/app/+item-page/simple/field-components/specific-field/date/item-page-date-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/date/item-page-date-field.component.spec.ts index 2adada582b..91addcca92 100644 --- a/src/app/+item-page/simple/field-components/specific-field/date/item-page-date-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/date/item-page-date-field.component.spec.ts @@ -31,7 +31,7 @@ describe('ItemPageDateFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemPageDateFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(mockField, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(mockField, mockValue); fixture.detectChanges(); })); diff --git a/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.spec.ts index d8abd39cf3..fd95ff4229 100644 --- a/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.spec.ts @@ -33,7 +33,7 @@ describe('GenericItemPageFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(GenericItemPageFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(mockField, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(mockField, mockValue); comp.fields = mockFields; comp.label = mockLabel; fixture.detectChanges(); diff --git a/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts index ea6e722c66..ebb46e6600 100644 --- a/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts @@ -39,7 +39,7 @@ describe('ItemPageFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemPageFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(mockField, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(mockField, mockValue); comp.fields = mockFields; comp.label = mockLabel; fixture.detectChanges(); diff --git a/src/app/+item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts index cb1ba6a4bc..7b4fc476b4 100644 --- a/src/app/+item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts @@ -31,7 +31,7 @@ describe('ItemPageTitleFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemPageTitleFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(mockField, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(mockField, mockValue); fixture.detectChanges(); })); diff --git a/src/app/+item-page/simple/field-components/specific-field/uri/item-page-uri-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/uri/item-page-uri-field.component.spec.ts index 4511f16aae..cb76487d38 100644 --- a/src/app/+item-page/simple/field-components/specific-field/uri/item-page-uri-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/uri/item-page-uri-field.component.spec.ts @@ -31,7 +31,7 @@ describe('ItemPageUriFieldComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemPageUriFieldComponent); comp = fixture.componentInstance; - comp.item = mockItemWithMetadataFieldAndValue(mockField, mockValue); + comp.itemRD$ = mockItemWithMetadataFieldAndValue(mockField, mockValue); fixture.detectChanges(); })); diff --git a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts index 65385b0442..5cebe69af4 100644 --- a/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts +++ b/src/app/+item-page/simple/related-entities/related-entities-search/related-entities-search.component.spec.ts @@ -29,7 +29,7 @@ describe('RelatedEntitiesSearchComponent', () => { fixture = TestBed.createComponent(RelatedEntitiesSearchComponent); comp = fixture.componentInstance; comp.relationType = mockRelationType; - comp.item = mockItem; + comp.itemRD$ = mockItem; comp.relationEntityType = mockRelationEntityType; fixture.detectChanges(); }); diff --git a/src/app/core/data/relationship-type.service.ts b/src/app/core/data/relationship-type.service.ts index aeb4fd50a9..c8cb417687 100644 --- a/src/app/core/data/relationship-type.service.ts +++ b/src/app/core/data/relationship-type.service.ts @@ -2,29 +2,16 @@ import { Injectable } from '@angular/core'; import { RequestService } from './request.service'; import { HALEndpointService } from '../shared/hal-endpoint.service'; import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; -import { hasValue, hasValueOperator, isNotEmptyOperator } from '../../shared/empty.util'; -import { distinctUntilChanged, filter, flatMap, map, switchMap, take, tap } from 'rxjs/operators'; -import { - configureRequest, - filterSuccessfulResponses, - getRemoteDataPayload, getResponseFromEntry, - getSucceededRemoteData -} from '../shared/operators'; -import { DeleteRequest, FindAllOptions, FindAllRequest, GetRequest, PostRequest, RestRequest } from './request.models'; +import { filter, find, map, switchMap } from 'rxjs/operators'; +import { configureRequest, getSucceededRemoteData } from '../shared/operators'; +import { FindAllOptions, FindAllRequest } from './request.models'; import { Observable } from 'rxjs/internal/Observable'; -import { RestResponse } from '../cache/response.models'; -import { Item } from '../shared/item.model'; -import { Relationship } from '../shared/item-relationships/relationship.model'; import { RelationshipType } from '../shared/item-relationships/relationship-type.model'; import { RemoteData } from './remote-data'; -import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest'; -import { zip as observableZip } from 'rxjs'; import { PaginatedList } from './paginated-list'; -import { ItemDataService } from './item-data.service'; -import { - compareArraysUsingIds, filterRelationsByTypeLabel, - relationsToItems -} from '../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { of as observableOf, combineLatest as observableCombineLatest } from 'rxjs'; +import { ItemType } from '../shared/item-relationships/item-type.model'; +import { isNotUndefined } from '../../shared/empty.util'; /** * The service handling all relationship requests @@ -62,13 +49,29 @@ export class RelationshipTypeService { * Get the RelationshipType for a relationship type by label * @param label */ - getRelationshipTypeByLabel(label: string): Observable { - return this.getAllRelationshipTypes({ currentPage: 1, elementsPerPage: Number.MAX_VALUE }).pipe( - map((typeListRD: RemoteData>) => - typeListRD.payload.page.find((type: RelationshipType) => - type.leftLabel === label || type.rightLabel === label - ) - ), + getRelationshipTypeByLabelAndTypes(label: string, firstType: string, secondType: string): Observable { + return this.getAllRelationshipTypes({ currentPage: 1, elementsPerPage: Number.MAX_VALUE }) + .pipe( + getSucceededRemoteData(), + /* Flatten the page so we can treat it like an observable */ + switchMap((typeListRD: RemoteData>) => typeListRD.payload.page), + switchMap((type: RelationshipType) => { + if (type.leftLabel === label) return this.checkType(type, firstType, secondType); + else if (type.rightLabel === label) return this.checkType(type, secondType, firstType); + else return []; + }), + ); + } + + // Check if relationship type matches the given types + // returns a void observable if there's not match + // returns an observable that emits the relationship type when there is a match + private checkType(type: RelationshipType, firstType: string, secondType: string): Observable { + const entityTypes = observableCombineLatest(type.leftType.pipe(getSucceededRemoteData()), type.rightType.pipe(getSucceededRemoteData())); + return entityTypes.pipe( + find(([leftTypeRD, rightTypeRD]: [RemoteData, RemoteData]) => leftTypeRD.payload.label === firstType && rightTypeRD.payload.label === secondType), + filter((types) => isNotUndefined(types)), + map(() => type) ); } -} +} \ No newline at end of file diff --git a/src/app/core/shared/item-relationships/item-type.model.ts b/src/app/core/shared/item-relationships/item-type.model.ts index e4f98ab653..a105c3034c 100644 --- a/src/app/core/shared/item-relationships/item-type.model.ts +++ b/src/app/core/shared/item-relationships/item-type.model.ts @@ -10,6 +10,8 @@ export class ItemType implements CacheableObject { */ id: string; + label: string; + /** * The link to the rest endpoint where this object can be found */ 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 d00d5e2c72..355ce7b83c 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 @@ -277,7 +277,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo modalComp.listId = this.listId; modalComp.relationship = this.model.relationship; modalComp.label = this.model.label; - modalComp.item = this.model.workspaceItem.item; + modalComp.itemRD$ = this.model.workspaceItem.item; } removeSelection(object: SearchResult) { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts index 5e4350cf8e..6972eb8e95 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { PaginatedList } from '../../../../../core/data/paginated-list'; import { SearchResult } from '../../../../search/search-result.model'; import { RemoteData } from '../../../../../core/data/remote-data'; @@ -24,7 +24,6 @@ import { RelationshipService } from '../../../../../core/data/relationship.servi import { Item } from '../../../../../core/shared/item.model'; import { RelationshipOptions } from '../../models/relationship-options.model'; import { combineLatest as observableCombineLatest } from 'rxjs'; -import { relationship } from '../../../../../core/cache/builders/build-decorators'; @Component({ selector: 'ds-dynamic-lookup-relation-modal', @@ -37,10 +36,10 @@ import { relationship } from '../../../../../core/cache/builders/build-decorator } ] }) -export class DsDynamicLookupRelationModalComponent implements OnInit { +export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy { label: string; relationship: RelationshipOptions; - item: Observable>; + itemRD$: Observable>; listId: string; resultsRD$: Observable>>>; searchConfig: PaginatedSearchOptions; @@ -49,12 +48,12 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { allSelected: boolean; someSelected$: Observable; selectAllLoading: boolean; + subscription; initialPagination = Object.assign(new PaginationComponentOptions(), { id: 'submission-relation-list', pageSize: 10 }); selection$: Observable; - relationshipType: Observable; constructor( public modal: NgbActiveModal, @@ -73,8 +72,6 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { this.routeService.setParameter('fixedFilterQuery', this.relationship.filter); this.routeService.setParameter('configuration', this.relationship.searchConfiguration); - this.relationshipType = this.relationshipTypeService.getRelationshipTypeByLabel(this.relationship.relationshipType); - this.selection$ = this.selectableListService.getSelectableList(this.listId).pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : [])); this.someSelected$ = this.selection$.pipe(map((selection) => isNotEmpty(selection))); this.resultsRD$ = this.searchConfigService.paginatedSearchOptions.pipe( @@ -149,15 +146,60 @@ export class DsDynamicLookupRelationModalComponent implements OnInit { select(selectableObject: SearchResult) { - observableCombineLatest(this.relationshipType, this.item).pipe(take(1)).subscribe( - ([type, itemRD]: [RelationshipType, RemoteData]) => { - const isSwitched = type.rightLabel === this.relationship.relationshipType; - if (isSwitched) { - this.relationshipService.addRelationship('1', selectableObject.indexableObject, itemRD.payload).pipe(getSucceededRemoteData()).subscribe(); - } else { - this.relationshipService.addRelationship('1', itemRD.payload, selectableObject.indexableObject).pipe(getSucceededRemoteData()).subscribe(); - } - } - ) + const relationshipType$: Observable = this.itemRD$.pipe( + getSucceededRemoteData(), + switchMap((itemRD: RemoteData) => { + const type1: string = itemRD.payload.firstMetadataValue('relationship.type'); + const type2: string = selectableObject.indexableObject.firstMetadataValue('relationship.type'); + return this.relationshipTypeService.getRelationshipTypeByLabelAndTypes(this.relationship.relationshipType, type1, type2); + })); + + this.subscription = observableCombineLatest(relationshipType$, this.itemRD$) + .pipe( + take(1), + switchMap(([type, itemRD]: [RelationshipType, RemoteData]) => { + const isSwitched = type.rightLabel === this.relationship.relationshipType; + let result; + if (isSwitched) { + result = this.relationshipService.addRelationship(type.id, selectableObject.indexableObject, itemRD.payload); + } else { + result = this.relationshipService.addRelationship(type.id, itemRD.payload, selectableObject.indexableObject); + } + console.log(result); + return result; + }) + ) + .subscribe(); + } + + + deselect(selectableObject: SearchResult) { + const relationshipType$: Observable = this.itemRD$.pipe( + getSucceededRemoteData(), + switchMap((itemRD: RemoteData) => { + const type1: string = itemRD.payload.firstMetadataValue('relationship.type'); + const type2: string = selectableObject.indexableObject.firstMetadataValue('relationship.type'); + return this.relationshipTypeService.getRelationshipTypeByLabelAndTypes(this.relationship.relationshipType, type1, type2); + })); + + this.subscription = observableCombineLatest(relationshipType$, this.itemRD$) + .pipe( + take(1), + switchMap(([type, itemRD]: [RelationshipType, RemoteData]) => { + const isSwitched = type.rightLabel === this.relationship.relationshipType; + if (isSwitched) { + return this.relationshipService.addRelationship(type.id, selectableObject.indexableObject, itemRD.payload); + } else { + return this.relationshipService.addRelationship(type.id, itemRD.payload, selectableObject.indexableObject); + } + }) + ) + .subscribe(); + } + + ngOnDestroy(): void { + if (hasValue(this.subscription)) { + this.subscription.unsubscribe(); + } } } \ No newline at end of file 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 7920e54b00..c35814b537 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 @@ -72,7 +72,7 @@ describe('ItemDetailPreviewComponent', () => { fixture = TestBed.createComponent(ItemDetailPreviewComponent); component = fixture.componentInstance; component.object = { hitHighlights: {} } as any; - component.item = mockItem; + component.itemRD$ = mockItem; component.separator = ', '; spyOn(component.item, 'getFiles').and.returnValue(mockItem.bitstreams); fixture.detectChanges(); diff --git a/src/backend/api.ts b/src/backend/api.ts index e1943b5d30..a4763f0be7 100644 --- a/src/backend/api.ts +++ b/src/backend/api.ts @@ -117,7 +117,7 @@ export function createMockApi() { const id = req.params.item_id; try { req.item_id = id; - req.item = ITEMS.items.find((item) => { + req.itemRD$ = ITEMS.items.find((item) => { return item.id === id; }); next(); @@ -127,7 +127,7 @@ export function createMockApi() { }); router.route('/items/:item_id').get((req, res) => { - res.json(toHALResponse(req, req.item)); + res.json(toHALResponse(req, req.itemRD$)); }); router.route('/bundles').get((req, res) => {