diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5
index 9afe280fa3..8d956d1a0e 100644
--- a/resources/i18n/en.json5
+++ b/resources/i18n/en.json5
@@ -853,7 +853,7 @@
"item.edit.tabs.relationships.head": "Item Relationships",
- "item.edit.tabs.relationships.title": "Item Edit - Relationships",
+ "item.edit.tabs.relationships.title": "Item Edit - Relationships",
"item.edit.tabs.status.buttons.authorizations.button": "Authorizations...",
@@ -1974,12 +1974,16 @@
"uploader.drag-message": "Drag & Drop your files here",
- "uploader.or": ", or ",
+ "uploader.or": ", or",
"uploader.processing": "Processing",
"uploader.queue-length": "Queue length",
+ "virtual-metadata.delete-item.info": "Select the types for which you want to save the virtual metadata as real metadata",
+
+ "virtual-metadata.delete-item.modal-head": "The virtual metadata of this relation",
+
"virtual-metadata.delete-relationship.modal-head": "Select the items for which you want to save the virtual metadata as real metadata",
}
diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.html b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.html
new file mode 100644
index 0000000000..5e7297409b
--- /dev/null
+++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.html
@@ -0,0 +1,98 @@
+
+
+
+
+
{{headerMessage | translate: {id: item.handle} }}
+
{{descriptionMessage | translate}}
+
+
+
+
+ 0" class="mb-4">
+
+ {{'virtual-metadata.delete-item.info' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{getRelationshipMessageKey(getLabel(type) | async) | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{metadata.metadataField}}
+
+
+ {{metadata.metadataValue.value}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{confirmMessage | translate}}
+
+
+ {{cancelMessage| translate}}
+
+
+
+
+
diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts
index 82d03f1f1b..00ae038dae 100644
--- a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts
+++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.spec.ts
@@ -1,44 +1,132 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { Item } from '../../../core/shared/item.model';
-import { RouterStub } from '../../../shared/testing/router-stub';
-import { of as observableOf } from 'rxjs';
-import { RemoteData } from '../../../core/data/remote-data';
-import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-import { RouterTestingModule } from '@angular/router/testing';
-import { TranslateModule } from '@ngx-translate/core';
-import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
-import { ActivatedRoute, Router } from '@angular/router';
-import { ItemDataService } from '../../../core/data/item-data.service';
-import { NotificationsService } from '../../../shared/notifications/notifications.service';
-import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { By } from '@angular/platform-browser';
-import { ItemDeleteComponent } from './item-delete.component';
-import { getItemEditPath } from '../../item-page-routing.module';
-import { RestResponse } from '../../../core/cache/response.models';
-import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import { ItemType } from '../../../core/shared/item-relationships/item-type.model';
+import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
+import {Item} from '../../../core/shared/item.model';
+import {RouterStub} from '../../../shared/testing/router-stub';
+import {of as observableOf} from 'rxjs';
+import {NotificationsServiceStub} from '../../../shared/testing/notifications-service-stub';
+import {CommonModule} from '@angular/common';
+import {FormsModule} from '@angular/forms';
+import {RouterTestingModule} from '@angular/router/testing';
+import {TranslateModule} from '@ngx-translate/core';
+import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
+import {ActivatedRoute, Router} from '@angular/router';
+import {ItemDataService} from '../../../core/data/item-data.service';
+import {NotificationsService} from '../../../shared/notifications/notifications.service';
+import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {By} from '@angular/platform-browser';
+import {ItemDeleteComponent} from './item-delete.component';
+import {getItemEditPath} from '../../item-page-routing.module';
+import {createSuccessfulRemoteDataObject} from '../../../shared/testing/utils';
+import {VarDirective} from '../../../shared/utils/var.directive';
+import {ObjectUpdatesService} from '../../../core/data/object-updates/object-updates.service';
+import {RelationshipService} from '../../../core/data/relationship.service';
+import {RelationshipType} from '../../../core/shared/item-relationships/relationship-type.model';
+import {RemoteData} from '../../../core/data/remote-data';
+import {PaginatedList} from '../../../core/data/paginated-list';
+import {PageInfo} from '../../../core/shared/page-info.model';
+import {EntityTypeService} from '../../../core/data/entity-type.service';
let comp: ItemDeleteComponent;
let fixture: ComponentFixture;
let mockItem;
+let itemType;
+let type1;
+let type2;
+let types;
+let relationships;
let itemPageUrl;
let routerStub;
let mockItemDataService: ItemDataService;
let routeStub;
+let objectUpdatesServiceStub;
+let relationshipService;
+let entityTypeService;
let notificationsServiceStub;
+let typesSelection;
describe('ItemDeleteComponent', () => {
beforeEach(async(() => {
mockItem = Object.assign(new Item(), {
id: 'fake-id',
+ uuid: 'fake-uuid',
handle: 'fake/handle',
lastModified: '2018',
isWithdrawn: true
});
+ itemType = Object.assign(new ItemType(), {
+ id: 'itemType',
+ uuid: 'itemType',
+ });
+
+ type1 = Object.assign(new RelationshipType(), {
+ id: '1',
+ uuid: 'type-1',
+ });
+
+ type2 = Object.assign(new RelationshipType(), {
+ id: '2',
+ uuid: 'type-2',
+ });
+
+ types = [type1, type2];
+
+ relationships = [
+ Object.assign(new Relationship(), {
+ id: '1',
+ uuid: 'relationship-1',
+ relationshipType: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ type1
+ )),
+ leftItem: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ mockItem,
+ )),
+ rightItem: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ Object.assign(new Item(), {})
+ )),
+ }),
+ Object.assign(new Relationship(), {
+ id: '2',
+ uuid: 'relationship-2',
+ relationshipType: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ type2
+ )),
+ leftItem: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ mockItem,
+ )),
+ rightItem: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ Object.assign(new Item(), {})
+ )),
+ }),
+ ];
+
itemPageUrl = `fake-url/${mockItem.id}`;
routerStub = Object.assign(new RouterStub(), {
url: `${itemPageUrl}/edit`
@@ -54,16 +142,56 @@ describe('ItemDeleteComponent', () => {
})
};
+ typesSelection = {
+ type1: false,
+ type2: true,
+ };
+
+ entityTypeService = jasmine.createSpyObj('entityTypeService',
+ {
+ getEntityTypeByLabel: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ itemType,
+ )),
+ getEntityTypeRelationships: observableOf(new RemoteData(
+ false,
+ false,
+ true,
+ null,
+ new PaginatedList(new PageInfo(), types),
+ )),
+ }
+ );
+
+ objectUpdatesServiceStub = {
+ initialize: () => {
+ // do nothing
+ },
+ isSelectedVirtualMetadata: (type) => observableOf(typesSelection[type]),
+ };
+
+ relationshipService = jasmine.createSpyObj('relationshipService',
+ {
+ getItemRelationshipsArray: observableOf(relationships),
+ }
+ );
+
notificationsServiceStub = new NotificationsServiceStub();
TestBed.configureTestingModule({
imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
- declarations: [ItemDeleteComponent],
+ declarations: [ItemDeleteComponent, VarDirective],
providers: [
{ provide: ActivatedRoute, useValue: routeStub },
{ provide: Router, useValue: routerStub },
{ provide: ItemDataService, useValue: mockItemDataService },
{ provide: NotificationsService, useValue: notificationsServiceStub },
+ { provide: ObjectUpdatesService, useValue: objectUpdatesServiceStub },
+ { provide: RelationshipService, useValue: relationshipService },
+ { provide: EntityTypeService, useValue: entityTypeService },
], schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
@@ -91,7 +219,8 @@ describe('ItemDeleteComponent', () => {
it('should call delete function from the ItemDataService', () => {
spyOn(comp, 'notify');
comp.performAction();
- expect(mockItemDataService.delete).toHaveBeenCalledWith(mockItem);
+ expect(mockItemDataService.delete)
+ .toHaveBeenCalledWith(mockItem, types.filter((type) => typesSelection[type]).map((type) => type.id));
expect(comp.notify).toHaveBeenCalled();
});
});
diff --git a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
index 2700b45475..6fe44c109b 100644
--- a/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
+++ b/src/app/+item-page/edit-item-page/item-delete/item-delete.component.ts
@@ -1,29 +1,323 @@
-import { Component } from '@angular/core';
-import { first } from 'rxjs/operators';
-import { AbstractSimpleItemActionComponent } from '../simple-item-action/abstract-simple-item-action.component';
-import { getItemEditPath } from '../../item-page-routing.module';
-import { RestResponse } from '../../../core/cache/response.models';
+import {Component, Input, OnInit} from '@angular/core';
+import {filter, first, map, switchMap, take} from 'rxjs/operators';
+import {AbstractSimpleItemActionComponent} from '../simple-item-action/abstract-simple-item-action.component';
+import {getItemEditPath} from '../../item-page-routing.module';
+import {NgbModal, NgbModalRef} from '@ng-bootstrap/ng-bootstrap';
+import {combineLatest as observableCombineLatest, combineLatest, Observable} from 'rxjs';
+import {RelationshipType} from '../../../core/shared/item-relationships/relationship-type.model';
+import {VirtualMetadata} from '../virtual-metadata/virtual-metadata.component';
+import {Relationship} from '../../../core/shared/item-relationships/relationship.model';
+import {getRemoteDataPayload, getSucceededRemoteData} from '../../../core/shared/operators';
+import {hasValue, isNotEmpty} from '../../../shared/empty.util';
+import {Item} from '../../../core/shared/item.model';
+import {MetadataValue} from '../../../core/shared/metadata.models';
+import {ViewMode} from '../../../core/shared/view-mode.model';
+import {ActivatedRoute, Router} from '@angular/router';
+import {NotificationsService} from '../../../shared/notifications/notifications.service';
+import {ItemDataService} from '../../../core/data/item-data.service';
+import {TranslateService} from '@ngx-translate/core';
+import {ObjectUpdatesService} from '../../../core/data/object-updates/object-updates.service';
+import {RelationshipService} from '../../../core/data/relationship.service';
+import {EntityTypeService} from '../../../core/data/entity-type.service';
@Component({
selector: 'ds-item-delete',
- templateUrl: '../simple-item-action/abstract-simple-item-action.component.html'
+ templateUrl: '../item-delete/item-delete.component.html'
})
/**
* Component responsible for rendering the item delete page
*/
-export class ItemDeleteComponent extends AbstractSimpleItemActionComponent {
+export class ItemDeleteComponent
+ extends AbstractSimpleItemActionComponent
+ implements OnInit {
+
+ /**
+ * The current url of this page
+ */
+ @Input() url: string;
protected messageKey = 'delete';
/**
- * Perform the delete action to the item
+ * The view-mode we're currently on
+ */
+ viewMode = ViewMode.ListElement;
+
+ /**
+ * A list of the relationship types for which this item has relations as an observable.
+ * The list doesn't contain duplicates.
+ */
+ types$: Observable;
+
+ /**
+ * A map which stores the relationships of this item for each type as observable lists
+ */
+ relationships$: Map>
+ = new Map>();
+
+ /**
+ * A map which stores the related item of each relationship of this item as an observable
+ */
+ relatedItems$: Map> = new Map>();
+
+ /**
+ * A map which stores the virtual metadata (of the related) item corresponding to each relationship of this item
+ * as an observable list
+ */
+ virtualMetadata$: Map> = new Map>();
+
+ /**
+ * Reference to NgbModal
+ */
+ public modalRef: NgbModalRef;
+
+ constructor(protected route: ActivatedRoute,
+ protected router: Router,
+ protected notificationsService: NotificationsService,
+ protected itemDataService: ItemDataService,
+ protected translateService: TranslateService,
+ protected modalService: NgbModal,
+ protected objectUpdatesService: ObjectUpdatesService,
+ protected relationshipService: RelationshipService,
+ protected entityTypeService: EntityTypeService,
+ ) {
+ super(
+ route,
+ router,
+ notificationsService,
+ itemDataService,
+ translateService,
+ );
+ }
+
+ /**
+ * Set up and initialize all fields
+ */
+ ngOnInit() {
+
+ super.ngOnInit();
+ this.url = this.router.url;
+
+ this.types$ = this.entityTypeService.getEntityTypeByLabel(
+ this.item.firstMetadataValue('relationship.type')
+ ).pipe(
+ getSucceededRemoteData(),
+ getRemoteDataPayload(),
+ switchMap((entityType) => this.entityTypeService.getEntityTypeRelationships(entityType.id)),
+ getSucceededRemoteData(),
+ getRemoteDataPayload(),
+ map((relationshipTypes) => relationshipTypes.page),
+ switchMap((types) =>
+ combineLatest(types.map((type) => this.getRelationships(type))).pipe(
+ map((relationships) =>
+ types.reduce((includedTypes, type, index) => {
+ if (!includedTypes.some((includedType) => includedType.id === type.id)
+ && !(relationships[index].length === 0)) {
+ return [...includedTypes, type];
+ } else {
+ return includedTypes;
+ }
+ }, [])
+ ),
+ )
+ ),
+ );
+
+ this.types$.pipe(
+ take(1),
+ ).subscribe((types) =>
+ this.objectUpdatesService.initialize(this.url, types, this.item.lastModified)
+ );
+ }
+
+ /**
+ * Open the modal which lists the virtual metadata of a relation
+ * @param content the html content of the modal
+ */
+ openVirtualMetadataModal(content: any) {
+ this.modalRef = this.modalService.open(content);
+ }
+
+ /**
+ * Close the modal which lists the virtual metadata of a relation
+ */
+ closeVirtualMetadataModal() {
+ this.modalRef.close();
+ }
+
+ /**
+ * Get the i18n message key for a relationship
+ * @param label The relationship type's label
+ */
+ getRelationshipMessageKey(label: string): string {
+ if (hasValue(label) && label.indexOf('Of') > -1) {
+ return `relationships.${label.substring(0, label.indexOf('Of') + 2)}`
+ } else {
+ return label;
+ }
+ }
+
+ /**
+ * Get the relationship type label relevant for this item as an observable
+ * @param relationshipType the relationship type to get the label for
+ */
+ getLabel(relationshipType: RelationshipType): Observable {
+
+ return this.getRelationships(relationshipType).pipe(
+ switchMap((relationships) =>
+ this.isLeftItem(relationships[0]).pipe(
+ map((isLeftItem) => isLeftItem ? relationshipType.leftwardType : relationshipType.rightwardType),
+ )
+ ),
+ )
+ }
+
+ /**
+ * Get the relationships of this item with a given type as an observable
+ * @param relationshipType the relationship type to filter the item's relationships on
+ */
+ getRelationships(relationshipType: RelationshipType): Observable {
+
+ if (!this.relationships$.has(relationshipType)) {
+ this.relationships$.set(
+ relationshipType,
+ this.relationshipService.getItemRelationshipsArray(this.item).pipe(
+ // filter on type
+ switchMap((relationships) =>
+ observableCombineLatest(
+ relationships.map((relationship) => this.getRelationshipType(relationship))
+ ).pipe(
+ map((types) => relationships.filter(
+ (relationship, index) => relationshipType.id === types[index].id
+ )),
+ )
+ ),
+ )
+ );
+ }
+
+ return this.relationships$.get(relationshipType);
+ }
+
+ /**
+ * Get the type of a given relationship as an observable
+ * @param relationship the relationship to get the type for
+ */
+ private getRelationshipType(relationship: Relationship): Observable {
+
+ return relationship.relationshipType.pipe(
+ getSucceededRemoteData(),
+ getRemoteDataPayload(),
+ filter((relationshipType: RelationshipType) => hasValue(relationshipType) && isNotEmpty(relationshipType.uuid))
+ );
+ }
+
+ /**
+ * Get the item this item is related to through a given relationship as an observable
+ * @param relationship the relationship to get the other item for
+ */
+ getRelatedItem(relationship: Relationship): Observable- {
+
+ if (!this.relatedItems$.has(relationship)) {
+
+ this.relatedItems$.set(
+ relationship,
+ this.isLeftItem(relationship).pipe(
+ switchMap((isLeftItem) => isLeftItem ? relationship.rightItem : relationship.leftItem),
+ getSucceededRemoteData(),
+ getRemoteDataPayload(),
+ ),
+ );
+ }
+
+ return this.relatedItems$.get(relationship);
+ }
+
+ /**
+ * Get the virtual metadata for a given relationship of the related item.
+ * @param relationship the relationship to get the virtual metadata for
+ */
+ getVirtualMetadata(relationship: Relationship): Observable
{
+
+ if (!this.virtualMetadata$.has(relationship)) {
+
+ this.virtualMetadata$.set(
+ relationship,
+ this.getRelatedItem(relationship).pipe(
+ map((relatedItem) =>
+ Object.entries(relatedItem.metadata)
+ .map(([key, value]) => value
+ .filter((metadata: MetadataValue) =>
+ metadata.authority && metadata.authority.endsWith(relationship.id))
+ .map((metadata: MetadataValue) => {
+ return {
+ metadataField: key,
+ metadataValue: metadata,
+ }
+ }))
+ .reduce((previous, current) => previous.concat(current))
+ ),
+ )
+ );
+ }
+
+ return this.virtualMetadata$.get(relationship);
+ }
+
+ /**
+ * Check whether this item is the left item of a given relationship, as an observable boolean
+ * @param relationship the relationship for which to check whether this item is the left item
+ */
+ private isLeftItem(relationship: Relationship): Observable {
+
+ return relationship.leftItem.pipe(
+ getSucceededRemoteData(),
+ getRemoteDataPayload(),
+ filter((item: Item) => hasValue(item) && isNotEmpty(item.uuid)),
+ map((leftItem) => leftItem.uuid === this.item.uuid)
+ );
+ }
+
+ /**
+ * Check whether a given relationship type is selected to save the corresponding virtual metadata
+ * @param type the relationship type for which to check whether it is selected
+ */
+ isSelected(type: RelationshipType): Observable {
+ return this.objectUpdatesService.isSelectedVirtualMetadata(this.url, this.item.uuid, type.uuid);
+ }
+
+ /**
+ * Select/deselect a given relationship type to save the corresponding virtual metadata
+ * @param type the relationship type to select/deselect
+ * @param selected whether the type should be selected
+ */
+ setSelected(type: RelationshipType, selected: boolean): void {
+ this.objectUpdatesService.setSelectedVirtualMetadata(this.url, this.item.uuid, type.uuid, selected);
+ }
+
+ /**
+ * Perform the delete operation
*/
performAction() {
- this.itemDataService.delete(this.item).pipe(first()).subscribe(
- (succeeded: boolean) => {
- this.notify(succeeded);
- }
- );
+
+ this.types$.pipe(
+ switchMap((types) =>
+ combineLatest(
+ types.map((type) => this.isSelected(type))
+ ).pipe(
+ map((selection) => types.filter(
+ (type, index) => selection[index]
+ )),
+ map((selectedTypes) => selectedTypes.map((type) => type.id)),
+ )
+ ),
+ ).subscribe((types) => {
+ this.itemDataService.delete(this.item, types).pipe(first()).subscribe(
+ (succeeded: boolean) => {
+ this.notify(succeeded);
+ }
+ );
+ });
}
/**
diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts
index d55b7353eb..82fdb82008 100644
--- a/src/app/core/data/data.service.ts
+++ b/src/app/core/data/data.service.ts
@@ -318,9 +318,11 @@ export abstract class DataService {
/**
* Delete an existing DSpace Object on the server
* @param dso The DSpace Object to be removed
- * Return an observable that emits true when the deletion was successful, false when it failed
+ * @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
+ * metadata should be saved as real metadata
+ * @return an observable that emits true when the deletion was successful, false when it failed
*/
- delete(dso: T): Observable {
+ delete(dso: T, copyVirtualMetadata?: string[]): Observable {
const requestId = this.requestService.generateRequestId();
const hrefObs = this.halService.getEndpoint(this.linkPath).pipe(
@@ -329,6 +331,13 @@ export abstract class DataService {
hrefObs.pipe(
find((href: string) => hasValue(href)),
map((href: string) => {
+ if (copyVirtualMetadata) {
+ copyVirtualMetadata.forEach((id) =>
+ href += (href.includes('?') ? '&' : '?')
+ + 'copyVirtualMetadata='
+ + id
+ );
+ }
const request = new DeleteByIDRequest(requestId, href, dso.uuid);
this.requestService.configure(request);
})
diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts
index db8f401687..0448c18ec6 100644
--- a/src/app/core/data/relationship.service.ts
+++ b/src/app/core/data/relationship.service.ts
@@ -1,35 +1,47 @@
-import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
-import { MemoizedSelector, select, Store } from '@ngrx/store';
-import { combineLatest, combineLatest as observableCombineLatest } from 'rxjs';
-import { distinctUntilChanged, filter, map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators';
-import { compareArraysUsingIds, paginatedRelationsToItems, relationsToItems } from '../../+item-page/simple/item-types/shared/item-relationships-utils';
-import { AppState, keySelector } from '../../app.reducer';
-import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
import { ReorderableRelationship } from '../../shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
-import { RemoveNameVariantAction, SetNameVariantAction } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions';
-import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer';
-import { NotificationsService } from '../../shared/notifications/notifications.service';
-import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
-import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
-import { configureRequest, getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators';
-import { SearchParam } from '../cache/models/search-param.model';
-import { ObjectCacheService } from '../cache/object-cache.service';
-import { DeleteRequest, FindListOptions, PostRequest, RestRequest } from './request.models';
-import { RestResponse } from '../cache/response.models';
-import { CoreState } from '../core.reducers';
-import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { RequestService } from './request.service';
import { HALEndpointService } from '../shared/hal-endpoint.service';
+import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
+import { hasValue, hasValueOperator, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
+import { distinctUntilChanged, filter, map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators';
+import {
+ configureRequest,
+ getRemoteDataPayload,
+ getResponseFromEntry,
+ getSucceededRemoteData
+} from '../shared/operators';
+import { DeleteRequest, FindListOptions, PostRequest, RestRequest } 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, RemoteDataState } from './remote-data';
+import { combineLatest, combineLatest as observableCombineLatest } from 'rxjs';
import { PaginatedList } from './paginated-list';
import { ItemDataService } from './item-data.service';
-import { Relationship } from '../shared/item-relationships/relationship.model';
-import { Item } from '../shared/item.model';
+import {
+ compareArraysUsingIds,
+ paginatedRelationsToItems,
+ relationsToItems
+} from '../../+item-page/simple/item-types/shared/item-relationships-utils';
+import { ObjectCacheService } from '../cache/object-cache.service';
import { DataService } from './data.service';
+import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
+import { MemoizedSelector, select, Store } from '@ngrx/store';
+import { CoreState } from '../core.reducers';
+import { NotificationsService } from '../../shared/notifications/notifications.service';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
-import { RequestService } from './request.service';
-import { Observable } from 'rxjs/internal/Observable';
+import { SearchParam } from '../cache/models/search-param.model';
+import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
+import { AppState, keySelector } from '../../app.reducer';
+import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer';
+import {
+ RemoveNameVariantAction,
+ SetNameVariantAction
+} from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions';
const relationshipListsStateSelector = (state: AppState) => state.relationshipLists;