From 4a749cf91de89223b93e301d89bb685f01615c20 Mon Sep 17 00:00:00 2001
From: Kristof De Langhe <kristof.delanghe@atmire.com>
Date: Wed, 3 Apr 2019 11:58:45 +0200
Subject: [PATCH] 61142: AbstractItemUpdate component and refactoring of
 item-metadata and item-relationships

---
 resources/i18n/en.json                        |  25 +++
 .../abstract-item-update.component.ts         | 174 ++++++++++++++++++
 .../item-metadata/item-metadata.component.ts  | 152 ++-------------
 .../item-relationships.component.html         |   2 +-
 .../item-relationships.component.ts           | 159 ++++------------
 5 files changed, 254 insertions(+), 258 deletions(-)
 create mode 100644 src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts

diff --git a/resources/i18n/en.json b/resources/i18n/en.json
index 8b7d15abfd..b64edd42d5 100644
--- a/resources/i18n/en.json
+++ b/resources/i18n/en.json
@@ -273,6 +273,31 @@
             "content": "Your changes to this item's metadata were saved."
           }
         }
+      },
+      "relationships": {
+        "discard-button": "Discard",
+        "reinstate-button": "Undo",
+        "save-button": "Save",
+        "edit": {
+          "buttons": {
+            "remove": "Remove",
+            "undo": "Undo changes"
+          }
+        },
+        "notifications": {
+          "outdated": {
+            "title": "Changed outdated",
+            "content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts"
+          },
+          "discarded": {
+            "title": "Changed discarded",
+            "content": "Your changes were discarded. To reinstate your changes click the 'Undo' button"
+          },
+          "saved": {
+            "title": "Relationships saved",
+            "content": "Your changes to this item's relationships were saved."
+          }
+        }
       }
     }
   },
diff --git a/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts b/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts
new file mode 100644
index 0000000000..3cc2a5ed84
--- /dev/null
+++ b/src/app/+item-page/edit-item-page/abstract-item-update/abstract-item-update.component.ts
@@ -0,0 +1,174 @@
+import { Component, Inject, OnInit } from '@angular/core';
+import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
+import { Observable } from 'rxjs/internal/Observable';
+import { Item } from '../../../core/shared/item.model';
+import { ItemDataService } from '../../../core/data/item-data.service';
+import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
+import { ActivatedRoute, Router } from '@angular/router';
+import { NotificationsService } from '../../../shared/notifications/notifications.service';
+import { TranslateService } from '@ngx-translate/core';
+import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
+import { first, map } from 'rxjs/operators';
+import { RemoteData } from '../../../core/data/remote-data';
+
+@Component({
+  selector: 'ds-abstract-item-update',
+  template: ``,
+})
+/**
+ * Abstract component for managing object updates of an item
+ */
+export abstract class AbstractItemUpdateComponent implements OnInit {
+  /**
+   * The item to display the edit page for
+   */
+  protected item: Item;
+  /**
+   * The current values and updates for all this item's metadata fields
+   */
+  protected updates$: Observable<FieldUpdates>;
+  /**
+   * The current url of this page
+   */
+  protected url: string;
+  /**
+   * Prefix for this component's notification translate keys
+   */
+  protected notificationsPrefix;
+  /**
+   * The time span for being able to undo discarding changes
+   */
+  protected discardTimeOut: number;
+
+  constructor(
+    protected itemService: ItemDataService,
+    protected objectUpdatesService: ObjectUpdatesService,
+    protected router: Router,
+    protected notificationsService: NotificationsService,
+    protected translateService: TranslateService,
+    @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
+    protected route: ActivatedRoute
+  ) {
+
+  }
+
+  /**
+   * Initialize common properties between item-update components
+   */
+  ngOnInit(): void {
+    this.route.parent.data.pipe(map((data) => data.item))
+      .pipe(
+        first(),
+        map((data: RemoteData<Item>) => data.payload)
+      ).subscribe((item: Item) => {
+      this.item = item;
+    });
+
+    this.discardTimeOut = this.EnvConfig.item.edit.undoTimeout;
+    this.url = this.router.url;
+    if (this.url.indexOf('?') > 0) {
+      this.url = this.url.substr(0, this.url.indexOf('?'));
+    }
+    this.hasChanges().pipe(first()).subscribe((hasChanges) => {
+      if (!hasChanges) {
+        this.initializeOriginalFields();
+      } else {
+        this.checkLastModified();
+      }
+    });
+
+    this.initializeNotificationsPrefix();
+  }
+
+  /**
+   * Initialize the prefix for notification messages
+   */
+  abstract initializeNotificationsPrefix(): void;
+
+  /**
+   * Sends all initial values of this item to the object updates service
+   */
+  abstract initializeOriginalFields(): void;
+
+  /**
+   * Prevent unnecessary rerendering so fields don't lose focus
+   */
+  trackUpdate(index, update: FieldUpdate) {
+    return update && update.field ? update.field.uuid : undefined;
+  }
+
+  /**
+   * Checks whether or not there are currently updates for this item
+   */
+  hasChanges(): Observable<boolean> {
+    return this.objectUpdatesService.hasUpdates(this.url);
+  }
+
+  /**
+   * Check if the current page is entirely valid
+   */
+  protected isValid() {
+    return this.objectUpdatesService.isValidPage(this.url);
+  }
+
+  /**
+   * Checks if the current item is still in sync with the version in the store
+   * If it's not, a notification is shown and the changes are removed
+   */
+  private checkLastModified() {
+    const currentVersion = this.item.lastModified;
+    this.objectUpdatesService.getLastModified(this.url).pipe(first()).subscribe(
+      (updateVersion: Date) => {
+        if (updateVersion.getDate() !== currentVersion.getDate()) {
+          this.notificationsService.warning(this.getNotificationTitle('outdated'), this.getNotificationContent('outdated'));
+          this.initializeOriginalFields();
+        }
+      }
+    );
+  }
+
+  /**
+   * Submit the current changes
+   */
+  abstract submit(): void;
+
+  /**
+   * Request the object updates service to discard all current changes to this item
+   * Shows a notification to remind the user that they can undo this
+   */
+  discard() {
+    const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), { timeOut: this.discardTimeOut });
+    this.objectUpdatesService.discardFieldUpdates(this.url, undoNotification);
+  }
+
+  /**
+   * Request the object updates service to undo discarding all changes to this item
+   */
+  reinstate() {
+    this.objectUpdatesService.reinstateFieldUpdates(this.url);
+  }
+
+  /**
+   * Checks whether or not the item is currently reinstatable
+   */
+  isReinstatable(): Observable<boolean> {
+    return this.objectUpdatesService.isReinstatable(this.url);
+  }
+
+  /**
+   * Get translated notification title
+   * @param key
+   */
+  protected getNotificationTitle(key: string) {
+    return this.translateService.instant(this.notificationsPrefix + key + '.title');
+  }
+
+  /**
+   * Get translated notification content
+   * @param key
+   */
+  protected getNotificationContent(key: string) {
+    return this.translateService.instant(this.notificationsPrefix + key + '.content');
+
+  }
+}
diff --git a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
index 6b3e05c818..7c9202c3b9 100644
--- a/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
+++ b/src/app/+item-page/edit-item-page/item-metadata/item-metadata.component.ts
@@ -6,8 +6,6 @@ import { ActivatedRoute, Router } from '@angular/router';
 import { cloneDeep } from 'lodash';
 import { Observable } from 'rxjs';
 import {
-  FieldUpdate,
-  FieldUpdates,
   Identifiable
 } from '../../../core/data/object-updates/object-updates.reducer';
 import { first, map, switchMap, take, tap } from 'rxjs/operators';
@@ -20,6 +18,7 @@ import { RegistryService } from '../../../core/registry/registry.service';
 import { MetadataField } from '../../../core/metadata/metadatafield.model';
 import { MetadatumViewModel } from '../../../core/shared/metadata.models';
 import { Metadata } from '../../../core/shared/metadata.utils';
+import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
 
 @Component({
   selector: 'ds-item-metadata',
@@ -29,28 +28,7 @@ import { Metadata } from '../../../core/shared/metadata.utils';
 /**
  * Component for displaying an item's metadata edit page
  */
-export class ItemMetadataComponent implements OnInit {
-
-  /**
-   * The item to display the edit page for
-   */
-  item: Item;
-  /**
-   * The current values and updates for all this item's metadata fields
-   */
-  updates$: Observable<FieldUpdates>;
-  /**
-   * The current url of this page
-   */
-  url: string;
-  /**
-   * The time span for being able to undo discarding changes
-   */
-  private discardTimeOut: number;
-  /**
-   * Prefix for this component's notification translate keys
-   */
-  private notificationsPrefix = 'item.edit.metadata.notifications.';
+export class ItemMetadataComponent extends AbstractItemUpdateComponent {
 
   /**
    * Observable with a list of strings with all existing metadata field keys
@@ -58,90 +36,54 @@ export class ItemMetadataComponent implements OnInit {
   metadataFields$: Observable<string[]>;
 
   constructor(
-    private itemService: ItemDataService,
-    private objectUpdatesService: ObjectUpdatesService,
-    private router: Router,
-    private notificationsService: NotificationsService,
-    private translateService: TranslateService,
+    protected itemService: ItemDataService,
+    protected objectUpdatesService: ObjectUpdatesService,
+    protected router: Router,
+    protected notificationsService: NotificationsService,
+    protected translateService: TranslateService,
     @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
-    private route: ActivatedRoute,
-    private metadataFieldService: RegistryService,
+    protected route: ActivatedRoute,
+    protected metadataFieldService: RegistryService,
   ) {
-
+    super(itemService, objectUpdatesService, router, notificationsService, translateService, EnvConfig, route);
   }
 
   /**
    * Set up and initialize all fields
    */
   ngOnInit(): void {
+    super.ngOnInit();
     this.metadataFields$ = this.findMetadataFields();
-    this.route.parent.data.pipe(map((data) => data.item))
-      .pipe(
-        first(),
-        map((data: RemoteData<Item>) => data.payload)
-      ).subscribe((item: Item) => {
-      this.item = item;
-    });
-
-    this.discardTimeOut = this.EnvConfig.item.edit.undoTimeout;
-    this.url = this.router.url;
-    if (this.url.indexOf('?') > 0) {
-      this.url = this.url.substr(0, this.url.indexOf('?'));
-    }
-    this.hasChanges().pipe(first()).subscribe((hasChanges) => {
-      if (!hasChanges) {
-        this.initializeOriginalFields();
-      } else {
-        this.checkLastModified();
-      }
-    });
     this.updates$ = this.objectUpdatesService.getFieldUpdates(this.url, this.item.metadataAsList);
   }
 
   /**
-   * Sends a new add update for a field to the object updates service
-   * @param metadata The metadata to add, if no parameter is supplied, create a new Metadatum
+   * Initialize the prefix for notification messages
    */
-  add(metadata: MetadatumViewModel = new MetadatumViewModel()) {
-    this.objectUpdatesService.saveAddFieldUpdate(this.url, metadata);
-
+  public initializeNotificationsPrefix(): void {
+    this.notificationsPrefix = 'item.edit.metadata.notifications.';
   }
 
   /**
-   * Request the object updates service to discard all current changes to this item
-   * Shows a notification to remind the user that they can undo this
-   */
-  discard() {
-    const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), { timeOut: this.discardTimeOut });
-    this.objectUpdatesService.discardFieldUpdates(this.url, undoNotification);
-  }
-
-  /**
-   * Request the object updates service to undo discarding all changes to this item
+   * Sends a new add update for a field to the object updates service
+   * @param metadata The metadata to add, if no parameter is supplied, create a new Metadatum
    */
-  reinstate() {
-    this.objectUpdatesService.reinstateFieldUpdates(this.url);
+  add(metadata: MetadatumViewModel = new MetadatumViewModel()) {
+    this.objectUpdatesService.saveAddFieldUpdate(this.url, metadata);
   }
 
   /**
    * Sends all initial values of this item to the object updates service
    */
-  private initializeOriginalFields() {
+  public initializeOriginalFields() {
     this.objectUpdatesService.initialize(this.url, this.item.metadataAsList, this.item.lastModified);
   }
 
-  /**
-   * Prevent unnecessary rerendering so fields don't lose focus
-   */
-  trackUpdate(index, update: FieldUpdate) {
-    return update && update.field ? update.field.uuid : undefined;
-  }
-
   /**
    * Requests all current metadata for this item and requests the item service to update the item
    * Makes sure the new version of the item is rendered on the page
    */
-  submit() {
+  public submit() {
     this.isValid().pipe(first()).subscribe((isValid) => {
       if (isValid) {
         const metadata$: Observable<Identifiable[]> = this.objectUpdatesService.getUpdatedFields(this.url, this.item.metadataAsList) as Observable<MetadatumViewModel[]>;
@@ -167,60 +109,6 @@ export class ItemMetadataComponent implements OnInit {
     });
   }
 
-  /**
-   * Checks whether or not there are currently updates for this item
-   */
-  hasChanges(): Observable<boolean> {
-    return this.objectUpdatesService.hasUpdates(this.url);
-  }
-
-  /**
-   * Checks whether or not the item is currently reinstatable
-   */
-  isReinstatable(): Observable<boolean> {
-    return this.objectUpdatesService.isReinstatable(this.url);
-  }
-
-  /**
-   * Checks if the current item is still in sync with the version in the store
-   * If it's not, a notification is shown and the changes are removed
-   */
-  private checkLastModified() {
-    const currentVersion = this.item.lastModified;
-    this.objectUpdatesService.getLastModified(this.url).pipe(first()).subscribe(
-      (updateVersion: Date) => {
-        if (updateVersion.getDate() !== currentVersion.getDate()) {
-          this.notificationsService.warning(this.getNotificationTitle('outdated'), this.getNotificationContent('outdated'));
-          this.initializeOriginalFields();
-        }
-      }
-    );
-  }
-
-  /**
-   * Check if the current page is entirely valid
-   */
-  private isValid() {
-    return this.objectUpdatesService.isValidPage(this.url);
-  }
-
-  /**
-   * Get translated notification title
-   * @param key
-   */
-  private getNotificationTitle(key: string) {
-    return this.translateService.instant(this.notificationsPrefix + key + '.title');
-  }
-
-  /**
-   * Get translated notification content
-   * @param key
-   */
-  private getNotificationContent(key: string) {
-    return this.translateService.instant(this.notificationsPrefix + key + '.content');
-
-  }
-
   /**
    * Method to request all metadata fields and convert them to a list of strings
    */
diff --git a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.html b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.html
index c95812b4bb..cfa3b8f415 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.html
+++ b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.html
@@ -19,7 +19,7 @@
   </div>
   <div *ngFor="let label of relationLabels$ | async" class="mb-2">
     <h5>{{label}}</h5>
-    <div *ngFor="let updateValue of ((getUpdatesByLabel(label) | async)| dsObjectValues)"
+    <div *ngFor="let updateValue of ((getUpdatesByLabel(label) | async)| dsObjectValues); trackBy: trackUpdate"
          ds-edit-in-place-relationship
          [fieldUpdate]="updateValue || {}"
          [url]="url"
diff --git a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
index 0bd1635ae1..66701e22b4 100644
--- a/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
+++ b/src/app/+item-page/edit-item-page/item-relationships/item-relationships.component.ts
@@ -1,51 +1,32 @@
-import { Component, Inject, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
 import { Item } from '../../../core/shared/item.model';
-import { FieldUpdate, FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
+import { FieldUpdates } from '../../../core/data/object-updates/object-updates.reducer';
 import { Observable } from 'rxjs/internal/Observable';
-import { ActivatedRoute, Router } from '@angular/router';
-import { ObjectUpdatesService } from '../../../core/data/object-updates/object-updates.service';
-import { distinctUntilChanged, filter, first, flatMap, map, startWith, switchMap, tap } from 'rxjs/operators';
+import { distinctUntilChanged, first, flatMap, map, switchMap } from 'rxjs/operators';
 import { zip as observableZip } from 'rxjs';
 import { RemoteData } from '../../../core/data/remote-data';
 import { PaginatedList } from '../../../core/data/paginated-list';
 import { Relationship } from '../../../core/shared/item-relationships/relationship.model';
 import { hasValue, hasValueOperator } from '../../../shared/empty.util';
 import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
-import { NotificationsService } from '../../../shared/notifications/notifications.service';
 import { RelationshipType } from '../../../core/shared/item-relationships/relationship-type.model';
 import {
   compareArraysUsingIds,
   filterRelationsByTypeLabel,
   relationsToItems
 } from '../../simple/item-types/shared/item.component';
-import { ItemDataService } from '../../../core/data/item-data.service';
 import { combineLatest as observableCombineLatest } from 'rxjs/internal/observable/combineLatest';
-import { TranslateService } from '@ngx-translate/core';
-import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
+import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component';
 
 @Component({
   selector: 'ds-item-relationships',
   styleUrls: ['./item-relationships.component.scss'],
   templateUrl: './item-relationships.component.html',
 })
-export class ItemRelationshipsComponent implements OnInit {
-
-  /**
-   * The item to display the edit page for
-   */
-  item: Item;
-  /**
-   * The current values and updates for all this item's metadata fields
-   */
-  updates$: Observable<FieldUpdates>;
-  /**
-   * The current url of this page
-   */
-  url: string;
-  /**
-   * Prefix for this component's notification translate keys
-   */
-  private notificationsPrefix = 'item.edit.metadata.notifications.';
+/**
+ * Component for displaying an item's relationships edit page
+ */
+export class ItemRelationshipsComponent extends AbstractItemUpdateComponent {
 
   /**
    * The labels of all different relations within this item
@@ -56,47 +37,20 @@ export class ItemRelationshipsComponent implements OnInit {
    * Resolved relationships and types together in one observable
    */
   resolvedRelsAndTypes$: Observable<[Relationship[], RelationshipType[]]>;
-  /**
-   * The time span for being able to undo discarding changes
-   */
-  private discardTimeOut: number;
-
-  constructor(private route: ActivatedRoute,
-              private router: Router,
-              private translateService: TranslateService,
-              @Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
-              private objectUpdatesService: ObjectUpdatesService,
-              private notificationsService: NotificationsService,
-              private itemDataService: ItemDataService) {
-  }
 
   ngOnInit(): void {
-    this.route.parent.data.pipe(map((data) => data.item))
-      .pipe(
-        first(),
-        map((data: RemoteData<Item>) => data.payload)
-      ).subscribe((item: Item) => {
-      this.item = item;
-    });
-    this.discardTimeOut = this.EnvConfig.item.edit.undoTimeout;
-    this.url = this.router.url;
-    if (this.url.indexOf('?') > 0) {
-      this.url = this.url.substr(0, this.url.indexOf('?'));
-    }
-    this.hasChanges().pipe(first()).subscribe((hasChanges) => {
-      if (!hasChanges) {
-        this.initializeOriginalFields();
-      } else {
-        this.checkLastModified();
-      }
-    });
+    super.ngOnInit();
+
     this.updates$ = this.getRelationships().pipe(
-      relationsToItems(this.item.id, this.itemDataService),
+      relationsToItems(this.item.id, this.itemService),
       switchMap((items: Item[]) => this.objectUpdatesService.getFieldUpdates(this.url, items))
     );
     this.initRelationshipObservables();
   }
 
+  /**
+   * Initialize the item's relationship observables for easier access across the component
+   */
   initRelationshipObservables() {
     const relationships$ = this.getRelationships();
 
@@ -119,72 +73,36 @@ export class ItemRelationshipsComponent implements OnInit {
   }
 
   /**
-   * Prevent unnecessary rerendering so fields don't lose focus
-   */
-  trackUpdate(index, update: FieldUpdate) {
-    return update && update.field ? update.field.uuid : undefined;
-  }
-
-  /**
-   * Checks whether or not there are currently updates for this item
-   */
-  hasChanges(): Observable<boolean> {
-    return this.objectUpdatesService.hasUpdates(this.url);
-  }
-
-  /**
-   * Checks whether or not the item is currently reinstatable
-   */
-  isReinstatable(): Observable<boolean> {
-    return this.objectUpdatesService.isReinstatable(this.url);
-  }
-
-  discard(): void {
-    const undoNotification = this.notificationsService.info(this.getNotificationTitle('discarded'), this.getNotificationContent('discarded'), { timeOut: this.discardTimeOut });
-    this.objectUpdatesService.discardFieldUpdates(this.url, undoNotification);
-  }
-
-  /**
-   * Request the object updates service to undo discarding all changes to this item
+   * Initialize the prefix for notification messages
    */
-  reinstate() {
-    this.objectUpdatesService.reinstateFieldUpdates(this.url);
+  public initializeNotificationsPrefix(): void {
+    this.notificationsPrefix = 'item.edit.relationships.notifications.';
   }
 
-  submit(): void {
+  public submit(): void {
     const updatedItems$ = this.getRelationships().pipe(
       first(),
-      relationsToItems(this.item.id, this.itemDataService),
+      relationsToItems(this.item.id, this.itemService),
       switchMap((items: Item[]) => this.objectUpdatesService.getUpdatedFields(this.url, items) as Observable<Item[]>)
     );
     // TODO: Delete relationships
   }
 
-  private initializeOriginalFields() {
+  /**
+   * Sends all initial values of this item to the object updates service
+   */
+  public initializeOriginalFields() {
     this.getRelationships().pipe(
       first(),
-      relationsToItems(this.item.id, this.itemDataService)
+      relationsToItems(this.item.id, this.itemService)
     ).subscribe((items: Item[]) => {
       this.objectUpdatesService.initialize(this.url, items, this.item.lastModified);
     });
   }
 
   /**
-   * Checks if the current item is still in sync with the version in the store
-   * If it's not, a notification is shown and the changes are removed
+   * Fetch all the relationships of the item
    */
-  private checkLastModified() {
-    const currentVersion = this.item.lastModified;
-    this.objectUpdatesService.getLastModified(this.url).pipe(first()).subscribe(
-      (updateVersion: Date) => {
-        if (updateVersion.getDate() !== currentVersion.getDate()) {
-          this.notificationsService.warning(this.getNotificationTitle('outdated'), this.getNotificationContent('outdated'));
-          this.initializeOriginalFields();
-        }
-      }
-    );
-  }
-
   public getRelationships(): Observable<Relationship[]> {
     return this.item.relationships.pipe(
       getSucceededRemoteData(),
@@ -195,34 +113,25 @@ export class ItemRelationshipsComponent implements OnInit {
     );
   }
 
+  /**
+   * Transform the item's relationships of a specific type into related items
+   * @param label   The relationship type's label
+   */
   public getRelatedItemsByLabel(label: string): Observable<Item[]> {
     return this.resolvedRelsAndTypes$.pipe(
       filterRelationsByTypeLabel(label),
-      relationsToItems(this.item.id, this.itemDataService)
+      relationsToItems(this.item.id, this.itemService)
     );
   }
 
+  /**
+   * Get FieldUpdates for the relationships of a specific type
+   * @param label   The relationship type's label
+   */
   public getUpdatesByLabel(label: string): Observable<FieldUpdates> {
     return this.getRelatedItemsByLabel(label).pipe(
       switchMap((items: Item[]) => this.objectUpdatesService.getFieldUpdatesExclusive(this.url, items))
     )
   }
 
-  /**
-   * Get translated notification title
-   * @param key
-   */
-  private getNotificationTitle(key: string) {
-    return this.translateService.instant(this.notificationsPrefix + key + '.title');
-  }
-
-  /**
-   * Get translated notification content
-   * @param key
-   */
-  private getNotificationContent(key: string) {
-    return this.translateService.instant(this.notificationsPrefix + key + '.content');
-
-  }
-
 }
-- 
GitLab