From 55e37a63bc91c95daeaa03959be99301df7d6b3c Mon Sep 17 00:00:00 2001
From: Kristof De Langhe <kristof.delanghe@atmire.com>
Date: Tue, 27 Nov 2018 14:20:24 +0100
Subject: [PATCH] 55946: discovery requests reset and reload and list updates

---
 .../collection-item-mapper.component.ts       | 40 +++++++++++++------
 .../search-service/search.service.ts          | 11 ++++-
 .../builders/remote-data-build.service.ts     |  6 +--
 src/app/core/data/collection-data.service.ts  | 16 ++++----
 src/app/core/data/item-data.service.ts        |  7 ++--
 src/app/core/data/request.service.ts          | 18 ++++-----
 .../object-collection.component.ts            |  1 -
 7 files changed, 59 insertions(+), 40 deletions(-)

diff --git a/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts b/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
index 9199e010b8..8058398884 100644
--- a/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
+++ b/src/app/+collection-page/collection-item-mapper/collection-item-mapper.component.ts
@@ -8,7 +8,7 @@ import { Collection } from '../../core/shared/collection.model';
 import { SearchConfigurationService } from '../../+search-page/search-service/search-configuration.service';
 import { PaginatedSearchOptions } from '../../+search-page/paginated-search-options.model';
 import { PaginatedList } from '../../core/data/paginated-list';
-import { map, switchMap, take } from 'rxjs/operators';
+import { map, switchMap, take, tap } from 'rxjs/operators';
 import { getSucceededRemoteData, toDSpaceObjectListRD } from '../../core/shared/operators';
 import { SearchService } from '../../+search-page/search-service/search.service';
 import { DSpaceObject } from '../../core/shared/dspace-object.model';
@@ -20,6 +20,10 @@ import { TranslateService } from '@ngx-translate/core';
 import { CollectionDataService } from '../../core/data/collection-data.service';
 import { isNotEmpty } from '../../shared/empty.util';
 import { RestResponse } from '../../core/cache/response.models';
+import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
+import { Actions, ofType } from '@ngrx/effects';
+import { IndexActionTypes } from '../../core/index/index.actions';
+import { RequestActionTypes } from '../../core/data/request.actions';
 
 @Component({
   selector: 'ds-collection-item-mapper',
@@ -64,6 +68,8 @@ export class CollectionItemMapperComponent implements OnInit {
    */
   defaultSortOptions: SortOptions = new SortOptions('dc.title', SortDirection.ASC);
 
+  shouldUpdate$: BehaviorSubject<boolean>;
+
   constructor(private route: ActivatedRoute,
               private router: Router,
               private searchConfigService: SearchConfigurationService,
@@ -86,25 +92,31 @@ export class CollectionItemMapperComponent implements OnInit {
    *  TODO: When the API support it, fetch items excluding the collection's scope (currently fetches all items)
    */
   loadItemLists() {
+    this.shouldUpdate$ = new BehaviorSubject<boolean>(true);
     const collectionAndOptions$ = observableCombineLatest(
       this.collectionRD$,
-      this.searchOptions$
+      this.searchOptions$,
+      this.shouldUpdate$
     );
     this.collectionItemsRD$ = collectionAndOptions$.pipe(
-      switchMap(([collectionRD, options]) => {
-        return this.collectionDataService.getMappedItems(collectionRD.payload.id, Object.assign(options, {
-          sort: this.defaultSortOptions
-        }))
+      switchMap(([collectionRD, options, shouldUpdate]) => {
+        if (shouldUpdate) {
+          return this.collectionDataService.getMappedItems(collectionRD.payload.id, Object.assign(options, {
+            sort: this.defaultSortOptions
+          }))
+        }
       })
     );
     this.mappingItemsRD$ = collectionAndOptions$.pipe(
-      switchMap(([collectionRD, options]) => {
-        return this.searchService.search(Object.assign(new PaginatedSearchOptions(options), {
-          query: this.buildQuery(collectionRD.payload.id, options.query),
-          scope: undefined,
-          dsoType: DSpaceObjectType.ITEM,
-          sort: this.defaultSortOptions
-        }));
+      switchMap(([collectionRD, options, shouldUpdate]) => {
+          if (shouldUpdate) {
+            return this.searchService.search(Object.assign(new PaginatedSearchOptions(options), {
+              query: this.buildQuery(collectionRD.payload.id, options.query),
+              scope: undefined,
+              dsoType: DSpaceObjectType.ITEM,
+              sort: this.defaultSortOptions
+            }));
+          }
       }),
       toDSpaceObjectListRD()
     );
@@ -151,10 +163,12 @@ export class CollectionItemMapperComponent implements OnInit {
           this.notificationsService.error(head, content);
         });
       }
+      this.shouldUpdate$.next(true);
     });
 
     this.collectionRD$.pipe(take(1)).subscribe((collectionRD: RemoteData<Collection>) => {
       this.collectionDataService.clearMappingItemsRequests(collectionRD.payload.id);
+      this.searchService.clearDiscoveryRequests();
     });
   }
 
diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts
index 275b0b3340..049e4b1542 100644
--- a/src/app/+search-page/search-service/search.service.ts
+++ b/src/app/+search-page/search-service/search.service.ts
@@ -7,7 +7,7 @@ import {
   Router,
   UrlSegmentGroup
 } from '@angular/router';
-import { map, switchMap, tap } from 'rxjs/operators';
+import { map, switchMap, take, tap } from 'rxjs/operators';
 import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service';
 import {
   FacetConfigSuccessResponse,
@@ -47,6 +47,9 @@ import { CommunityDataService } from '../../core/data/community-data.service';
 import { ViewMode } from '../../core/shared/view-mode.model';
 import { ResourceType } from '../../core/shared/resource-type';
 import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
+import { Store } from '@ngrx/store';
+import { IndexName, IndexState } from '../../core/index/index.reducer';
+import { RemoveFromIndexBySubstringAction } from '../../core/index/index.actions';
 
 /**
  * Service that performs all general actions that have to do with the search page
@@ -319,6 +322,12 @@ export class SearchService implements OnDestroy {
     return '/' + g.toString();
   }
 
+  clearDiscoveryRequests() {
+    this.halService.getEndpoint(this.searchLinkPath).pipe(take(1)).subscribe((href: string) => {
+      this.requestService.removeByHrefSubstring(href);
+    });
+  }
+
   /**
    * Unsubscribe from the subscription
    */
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 52ec4382ae..c22b63f618 100644
--- a/src/app/core/cache/builders/remote-data-build.service.ts
+++ b/src/app/core/cache/builders/remote-data-build.service.ts
@@ -6,7 +6,7 @@ import {
 } from 'rxjs';
 import { Injectable } from '@angular/core';
 import { distinctUntilChanged, first, flatMap, map, startWith, switchMap } from 'rxjs/operators';
-import { hasValue, hasValueOperator, isEmpty, isNotEmpty } from '../../../shared/empty.util';
+import { hasValue, hasValueOperator, isEmpty, isNotEmpty, isNotEmptyOperator } from '../../../shared/empty.util';
 import { PaginatedList } from '../../data/paginated-list';
 import { RemoteData } from '../../data/remote-data';
 import { RemoteDataError } from '../../data/remote-data-error';
@@ -86,8 +86,8 @@ export class RemoteDataBuildService {
   toRemoteDataObservable<T>(requestEntry$: Observable<RequestEntry>, payload$: Observable<T>) {
     return observableCombineLatest(requestEntry$, payload$).pipe(
       map(([reqEntry, payload]) => {
-        const requestPending = hasValue(reqEntry.requestPending) ? reqEntry.requestPending : true;
-        const responsePending = hasValue(reqEntry.responsePending) ? reqEntry.responsePending : false;
+        const requestPending = hasValue(reqEntry) && hasValue(reqEntry.requestPending) ? reqEntry.requestPending : true;
+        const responsePending = hasValue(reqEntry) && hasValue(reqEntry.responsePending) ? reqEntry.responsePending : false;
         let isSuccessful: boolean;
         let error: RemoteDataError;
         if (hasValue(reqEntry) && hasValue(reqEntry.response)) {
diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts
index bc28ccc98c..e9ae5d38a5 100644
--- a/src/app/core/data/collection-data.service.ts
+++ b/src/app/core/data/collection-data.service.ts
@@ -1,9 +1,9 @@
 import { Injectable } from '@angular/core';
-import { MemoizedSelector, select, Store } from '@ngrx/store';
+import { Action, Store } from '@ngrx/store';
 import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
 import { NormalizedCollection } from '../cache/models/normalized-collection.model';
 import { ObjectCacheService } from '../cache/object-cache.service';
-import { coreSelector, CoreState } from '../core.reducers';
+import { CoreState } from '../core.reducers';
 import { Collection } from '../shared/collection.model';
 import { ComColDataService } from './comcol-data.service';
 import { CommunityDataService } from './community-data.service';
@@ -12,7 +12,7 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
 import { Observable } from 'rxjs';
 import { RemoteData } from './remote-data';
 import { PaginatedList } from './paginated-list';
-import { distinctUntilChanged, map, mergeMap, switchMap, take } from 'rxjs/operators';
+import { distinctUntilChanged, map, take, tap } from 'rxjs/operators';
 import { hasValue, isNotEmptyOperator } from '../../shared/empty.util';
 import { GetRequest } from './request.models';
 import { configureRequest } from '../shared/operators';
@@ -22,9 +22,8 @@ import { ResponseParsingService } from './parsing.service';
 import { DSpaceObject } from '../shared/dspace-object.model';
 import { DSOResponseParsingService } from './dso-response-parsing.service';
 import { IndexName, IndexState } from '../index/index.reducer';
-import { RemoveFromIndexBySubstringAction } from '../index/index.actions';
-import { pathSelector } from '../shared/selectors';
-import { RequestState } from './request.reducer';
+import { IndexActionTypes, RemoveFromIndexBySubstringAction } from '../index/index.actions';
+import { Actions, ofType } from '@ngrx/effects';
 
 @Injectable()
 export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
@@ -50,6 +49,8 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
   }
 
   getMappedItems(collectionId: string, searchOptions?: PaginatedSearchOptions): Observable<RemoteData<PaginatedList<DSpaceObject>>> {
+    const requestUuid = this.requestService.generateRequestId();
+
     const href$ = this.getMappingItemsEndpoint(collectionId).pipe(
       isNotEmptyOperator(),
       distinctUntilChanged(),
@@ -58,7 +59,7 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
 
     href$.pipe(
       map((endpoint: string) => {
-        const request = new GetRequest(this.requestService.generateRequestId(), endpoint);
+        const request = new GetRequest(requestUuid, endpoint);
         return Object.assign(request, {
           getResponseParser(): GenericConstructor<ResponseParsingService> {
             return DSOResponseParsingService;
@@ -74,7 +75,6 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
   clearMappingItemsRequests(collectionId: string) {
     this.getMappingItemsEndpoint(collectionId).pipe(take(1)).subscribe((href: string) => {
       this.requestService.removeByHrefSubstring(href);
-      this.indexStore.dispatch(new RemoveFromIndexBySubstringAction(IndexName.REQUEST, href));
     });
   }
 
diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts
index 15dc01d03a..c1a46cde9a 100644
--- a/src/app/core/data/item-data.service.ts
+++ b/src/app/core/data/item-data.service.ts
@@ -1,5 +1,5 @@
 
-import { distinctUntilChanged, map, filter, switchMap } from 'rxjs/operators';
+import { distinctUntilChanged, map, filter, switchMap, tap } from 'rxjs/operators';
 import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
 import { Observable } from 'rxjs';
@@ -21,6 +21,7 @@ import { configureRequest, filterSuccessfulResponses, getResponseFromEntry } fro
 import { RemoteData } from './remote-data';
 import { PaginatedList } from './paginated-list';
 import { Collection } from '../shared/collection.model';
+import { RequestEntry } from './request.reducer';
 
 @Injectable()
 export class ItemDataService extends DataService<NormalizedItem, Item> {
@@ -66,7 +67,7 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
       distinctUntilChanged(),
       map((endpointURL: string) => new DeleteRequest(this.requestService.generateRequestId(), endpointURL)),
       configureRequest(this.requestService),
-      switchMap((request: RestRequest) => this.requestService.getByHref(request.href)),
+      switchMap((request: RestRequest) => this.requestService.getByUUID(request.uuid)),
       getResponseFromEntry()
     );
   }
@@ -77,7 +78,7 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
       distinctUntilChanged(),
       map((endpointURL: string) => new PostRequest(this.requestService.generateRequestId(), endpointURL)),
       configureRequest(this.requestService),
-      switchMap((request: RestRequest) => this.requestService.getByHref(request.href)),
+      switchMap((request: RestRequest) => this.requestService.getByUUID(request.uuid)),
       getResponseFromEntry()
     );
   }
diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts
index a447df3051..9e8f28e1b9 100644
--- a/src/app/core/data/request.service.ts
+++ b/src/app/core/data/request.service.ts
@@ -31,7 +31,7 @@ import { RequestEntry } from './request.reducer';
 import { CommitSSBAction } from '../cache/server-sync-buffer.actions';
 import { RestRequestMethod } from './rest-request-method';
 import { getResponseFromEntry } from '../shared/operators';
-import { AddToIndexAction } from '../index/index.actions';
+import { AddToIndexAction, RemoveFromIndexBySubstringAction } from '../index/index.actions';
 
 @Injectable()
 export class RequestService {
@@ -39,7 +39,8 @@ export class RequestService {
 
   constructor(private objectCache: ObjectCacheService,
               private uuidService: UUIDService,
-              private store: Store<CoreState>) {
+              private store: Store<CoreState>,
+              private indexStore: Store<IndexState>) {
   }
 
   private entryFromUUIDSelector(uuid: string): MemoizedSelector<CoreState, RequestEntry> {
@@ -138,22 +139,17 @@ export class RequestService {
     }
   }
 
-  removeByHref(href: string) {
-    this.store.pipe(
-      select(this.uuidFromHrefSelector(href))
-    ).subscribe((uuid: string) => {
-      this.removeByUuid(uuid);
-    });
-  }
-
   removeByHrefSubstring(href: string) {
     this.store.pipe(
-      select(this.uuidsFromHrefSubstringSelector(pathSelector<CoreState, IndexState>(coreSelector, 'index'), IndexName.REQUEST, href))
+      select(this.uuidsFromHrefSubstringSelector(pathSelector<CoreState, IndexState>(coreSelector, 'index'), IndexName.REQUEST, href)),
+      take(1)
     ).subscribe((uuids: string[]) => {
       for (const uuid of uuids) {
         this.removeByUuid(uuid);
       }
     });
+    this.requestsOnTheirWayToTheStore = this.requestsOnTheirWayToTheStore.filter((reqHref: string) => reqHref.indexOf(href) < 0);
+    this.indexStore.dispatch(new RemoveFromIndexBySubstringAction(IndexName.REQUEST, href));
   }
 
   removeByUuid(uuid: string) {
diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts
index 4e46aeaeab..0018c55c7f 100644
--- a/src/app/shared/object-collection/object-collection.component.ts
+++ b/src/app/shared/object-collection/object-collection.component.ts
@@ -77,7 +77,6 @@ export class ObjectCollectionComponent implements OnChanges, OnInit {
           this.currentMode = params.view;
         }
       });
-    console.log(this.objects);
   }
 
   /**
-- 
GitLab