diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html
index 6f1cc41a1e..55d1e304d0 100644
--- a/src/app/+my-dspace-page/my-dspace-page.component.html
+++ b/src/app/+my-dspace-page/my-dspace-page.component.html
@@ -6,6 +6,7 @@
[configurationList]="(configurationList$ | async)"
[resultCount]="(resultsRD$ | async)?.payload.totalElements"
[viewModeList]="viewModeList"
+ [refreshFilters]="refreshFilters.asObservable()"
[inPlaceSearch]="inPlaceSearch">
@@ -39,7 +41,8 @@
+ [context]="context$ | async"
+ (contentChange)="onResultsContentChange()">
diff --git a/src/app/+my-dspace-page/my-dspace-page.component.ts b/src/app/+my-dspace-page/my-dspace-page.component.ts
index 0f08795cdc..5ee2a47d9f 100644
--- a/src/app/+my-dspace-page/my-dspace-page.component.ts
+++ b/src/app/+my-dspace-page/my-dspace-page.component.ts
@@ -7,7 +7,7 @@ import {
OnInit
} from '@angular/core';
-import { BehaviorSubject, Observable, Subscription } from 'rxjs';
+import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';
import { map, switchMap, tap, } from 'rxjs/operators';
import { PaginatedList } from '../core/data/paginated-list.model';
@@ -101,6 +101,11 @@ export class MyDSpacePageComponent implements OnInit {
*/
context$: Observable;
+ /**
+ * Emit an event every time search sidebars must refresh their contents.
+ */
+ refreshFilters: Subject = new Subject();
+
constructor(private service: SearchService,
private sidebarService: SidebarService,
private windowService: HostWindowService,
@@ -148,6 +153,14 @@ export class MyDSpacePageComponent implements OnInit {
}
+ /**
+ * Handle the contentChange event from within the my dspace content.
+ * Notify search sidebars to refresh their content.
+ */
+ onResultsContentChange() {
+ this.refreshFilters.next();
+ }
+
/**
* Set the sidebar to a collapsed state
*/
@@ -184,5 +197,6 @@ export class MyDSpacePageComponent implements OnInit {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
+ this.refreshFilters.complete();
}
}
diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html
index 3a829e6ece..2710285f0d 100644
--- a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html
+++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html
@@ -5,7 +5,8 @@
[sortConfig]="searchConfig.sort"
[objects]="searchResults"
[hideGear]="true"
- [context]="context">
+ [context]="context"
+ (contentChange)="contentChange.emit()">
diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts
index 35b13c8bae..32b6d9c9f7 100644
--- a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts
+++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts
@@ -1,4 +1,4 @@
-import { Component, Input } from '@angular/core';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { fadeIn, fadeInOut } from '../../shared/animations/fade';
@@ -41,6 +41,12 @@ export class MyDSpaceResultsComponent {
* The current context for the search results
*/
@Input() context: Context;
+
+ /**
+ * Emit when one of the results has changed.
+ */
+ @Output() contentChange = new EventEmitter();
+
/**
* A boolean representing if search results entry are separated by a line
*/
diff --git a/src/app/core/tasks/claimed-task-data.service.spec.ts b/src/app/core/tasks/claimed-task-data.service.spec.ts
index 977590fbed..ab9727592e 100644
--- a/src/app/core/tasks/claimed-task-data.service.spec.ts
+++ b/src/app/core/tasks/claimed-task-data.service.spec.ts
@@ -11,11 +11,10 @@ import { ClaimedTaskDataService } from './claimed-task-data.service';
import { of as observableOf } from 'rxjs/internal/observable/of';
import { FindListOptions } from '../data/request.models';
import { RequestParam } from '../cache/models/request-param.model';
-import { followLink } from '../../shared/utils/follow-link-config.model';
import { getTestScheduler } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
-import {createSuccessfulRemoteDataObject$} from '../../shared/remote-data.utils';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
describe('ClaimedTaskDataService', () => {
let scheduler: TestScheduler;
@@ -120,13 +119,7 @@ describe('ClaimedTaskDataService', () => {
new RequestParam('uuid', 'a0db0fde-1d12-4d43-bd0d-0f43df8d823c')
];
- expect(service.searchTask).toHaveBeenCalledWith('findByItem',
- findListOptions,
- followLink('workflowitem',
- null,
- true,
- false,
- true));
+ expect(service.searchTask).toHaveBeenCalledWith('findByItem', findListOptions);
});
});
});
diff --git a/src/app/core/tasks/claimed-task-data.service.ts b/src/app/core/tasks/claimed-task-data.service.ts
index f2d5c94585..9cfd5a44d6 100644
--- a/src/app/core/tasks/claimed-task-data.service.ts
+++ b/src/app/core/tasks/claimed-task-data.service.ts
@@ -16,7 +16,6 @@ import { CLAIMED_TASK } from './models/claimed-task-object.resource-type';
import { ProcessTaskResponse } from './models/process-task-response';
import { TasksService } from './tasks.service';
import { RemoteData } from '../data/remote-data';
-import { followLink } from '../../shared/utils/follow-link-config.model';
import { FindListOptions } from '../data/request.models';
import { RequestParam } from '../cache/models/request-param.model';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
@@ -116,12 +115,7 @@ export class ClaimedTaskDataService extends TasksService {
options.searchParams = [
new RequestParam('uuid', uuid)
];
- return this.searchTask('findByItem', options, followLink('workflowitem',
- null,
- true,
- false,
- true))
- .pipe(getFirstSucceededRemoteData());
+ return this.searchTask('findByItem', options).pipe(getFirstSucceededRemoteData());
}
}
diff --git a/src/app/core/tasks/pool-task-data.service.spec.ts b/src/app/core/tasks/pool-task-data.service.spec.ts
index 07fa5a9d66..7279c96e5c 100644
--- a/src/app/core/tasks/pool-task-data.service.spec.ts
+++ b/src/app/core/tasks/pool-task-data.service.spec.ts
@@ -11,11 +11,10 @@ import { PoolTaskDataService } from './pool-task-data.service';
import { getTestScheduler } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing';
import { of as observableOf } from 'rxjs/internal/observable/of';
-import { followLink } from '../../shared/utils/follow-link-config.model';
import { FindListOptions } from '../data/request.models';
import { RequestParam } from '../cache/models/request-param.model';
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
-import {createSuccessfulRemoteDataObject$} from '../../shared/remote-data.utils';
+import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
describe('PoolTaskDataService', () => {
let scheduler: TestScheduler;
@@ -74,12 +73,7 @@ describe('PoolTaskDataService', () => {
new RequestParam('uuid', 'a0db0fde-1d12-4d43-bd0d-0f43df8d823c')
];
- expect(service.searchTask).toHaveBeenCalledWith('findByItem', findListOptions,
- followLink('workflowitem',
- null,
- true,
- false,
- true));
+ expect(service.searchTask).toHaveBeenCalledWith('findByItem', findListOptions);
});
});
diff --git a/src/app/core/tasks/pool-task-data.service.ts b/src/app/core/tasks/pool-task-data.service.ts
index 83aad10fe5..d44e402e7f 100644
--- a/src/app/core/tasks/pool-task-data.service.ts
+++ b/src/app/core/tasks/pool-task-data.service.ts
@@ -15,10 +15,9 @@ import { PoolTask } from './models/pool-task-object.model';
import { POOL_TASK } from './models/pool-task-object.resource-type';
import { TasksService } from './tasks.service';
import { RemoteData } from '../data/remote-data';
-import { followLink } from '../../shared/utils/follow-link-config.model';
import { FindListOptions } from '../data/request.models';
import { RequestParam } from '../cache/models/request-param.model';
-import { getFirstSucceededRemoteData } from '../shared/operators';
+import { getFirstCompletedRemoteData } from '../shared/operators';
/**
* The service handling all REST requests for PoolTask
@@ -71,12 +70,7 @@ export class PoolTaskDataService extends TasksService {
options.searchParams = [
new RequestParam('uuid', uuid)
];
- return this.searchTask('findByItem', options, followLink('workflowitem',
- null,
- true,
- false,
- true))
- .pipe(getFirstSucceededRemoteData());
+ return this.searchTask('findByItem', options).pipe(getFirstCompletedRemoteData());
}
/**
diff --git a/src/app/shared/mydspace-actions/mydspace-reloadable-actions.ts b/src/app/shared/mydspace-actions/mydspace-reloadable-actions.ts
index c24d493d6b..7043191915 100644
--- a/src/app/shared/mydspace-actions/mydspace-reloadable-actions.ts
+++ b/src/app/shared/mydspace-actions/mydspace-reloadable-actions.ts
@@ -1,7 +1,7 @@
import { Router } from '@angular/router';
import { Component, Injector, OnInit } from '@angular/core';
-import { map, switchMap, tap} from 'rxjs/operators';
+import { map, switchMap, take, tap } from 'rxjs/operators';
import { RemoteData } from '../../core/data/remote-data';
import { DataService } from '../../core/data/data.service';
@@ -64,6 +64,7 @@ export abstract class MyDSpaceReloadableActionsComponent {
this.processing$.next(true);
return this.actionExecution().pipe(
+ take(1),
switchMap((res: ProcessTaskResponse) => {
if (res.hasSucceeded) {
return this._reloadObject().pipe(
@@ -137,7 +138,7 @@ export abstract class MyDSpaceReloadableActionsComponent {
- return dso ? this.convertReloadedObject(dso) : dso;
+ return dso ? this.convertReloadedObject(dso) : dso;
}));
}
diff --git a/src/app/shared/object-collection/object-collection.component.html b/src/app/shared/object-collection/object-collection.component.html
index e696170a6f..f2778757ef 100644
--- a/src/app/shared/object-collection/object-collection.component.html
+++ b/src/app/shared/object-collection/object-collection.component.html
@@ -18,6 +18,7 @@
[importable]="importable"
[importConfig]="importConfig"
(importObject)="importObject.emit($event)"
+ (contentChange)="contentChange.emit()"
*ngIf="(currentMode$ | async) === viewModeEnum.ListElement">
diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts
index ffb5c42880..52881f5eaf 100644
--- a/src/app/shared/object-collection/object-collection.component.ts
+++ b/src/app/shared/object-collection/object-collection.component.ts
@@ -53,6 +53,11 @@ export class ObjectCollectionComponent implements OnInit {
@Output() deselectObject: EventEmitter = new EventEmitter();
@Output() selectObject: EventEmitter = new EventEmitter();
+ /**
+ * Emit when one of the collection's object has changed.
+ */
+ @Output() contentChange = new EventEmitter();
+
/**
* Whether or not to add an import button to the object elements
*/
diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
index fb58c2c83d..51468993c1 100644
--- a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
+++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts
@@ -1,4 +1,14 @@
-import { Component, ComponentFactoryResolver, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import {
+ Component,
+ ComponentFactoryResolver,
+ ElementRef,
+ Input,
+ OnDestroy,
+ OnInit,
+ Output,
+ ViewChild,
+ EventEmitter
+} from '@angular/core';
import { ListableObject } from '../listable-object.model';
import { ViewMode } from '../../../../core/shared/view-mode.model';
import { Context } from '../../../../core/shared/context.model';
@@ -76,6 +86,11 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnDestroy
*/
@ViewChild('badges', { static: true }) badges: ElementRef;
+ /**
+ * Emit when the listable object has been reloaded.
+ */
+ @Output() contentChange = new EventEmitter();
+
/**
* Whether or not the "Private" badge should be displayed for this listable object
*/
@@ -141,6 +156,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnDestroy
componentRef.destroy();
this.object = reloadedObject;
this.instantiateComponent(reloadedObject);
+ this.contentChange.emit(reloadedObject);
}
});
}
diff --git a/src/app/shared/object-list/object-list.component.html b/src/app/shared/object-list/object-list.component.html
index 4aecaaac8f..331ff1cb28 100644
--- a/src/app/shared/object-list/object-list.component.html
+++ b/src/app/shared/object-list/object-list.component.html
@@ -22,7 +22,9 @@
[importConfig]="importConfig"
(importObject)="importObject.emit($event)">
+ [listID]="selectionConfig?.listId"
+ (contentChange)="contentChange.emit()"
+ >
diff --git a/src/app/shared/object-list/object-list.component.ts b/src/app/shared/object-list/object-list.component.ts
index b58c8b358e..6f4caae939 100644
--- a/src/app/shared/object-list/object-list.component.ts
+++ b/src/app/shared/object-list/object-list.component.ts
@@ -76,6 +76,11 @@ export class ObjectListComponent {
*/
@Input() importConfig: { importLabel: string };
+ /**
+ * Emit when one of the listed object has changed.
+ */
+ @Output() contentChange = new EventEmitter();
+
/**
* The current listable objects
*/
diff --git a/src/app/shared/search/search-filters/search-filters.component.spec.ts b/src/app/shared/search/search-filters/search-filters.component.spec.ts
index aaea82df27..2dd810db63 100644
--- a/src/app/shared/search/search-filters/search-filters.component.spec.ts
+++ b/src/app/shared/search/search-filters/search-filters.component.spec.ts
@@ -7,7 +7,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { SearchFilterService } from '../../../core/shared/search/search-filter.service';
import { SearchFiltersComponent } from './search-filters.component';
import { SearchService } from '../../../core/shared/search/search.service';
-import { of as observableOf } from 'rxjs';
+import { of as observableOf, Subject } from 'rxjs';
import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component';
import { SearchConfigurationServiceStub } from '../../testing/search-configuration-service.stub';
@@ -66,4 +66,26 @@ describe('SearchFiltersComponent', () => {
});
});
+ describe('when refreshSearch observable is present and emit events', () => {
+
+ let refreshFiltersEmitter: Subject;
+
+ beforeEach(() => {
+ spyOn(comp, 'initFilters').and.callFake(() => { /****/});
+
+ refreshFiltersEmitter = new Subject();
+ comp.refreshFilters = refreshFiltersEmitter.asObservable();
+ comp.ngOnInit();
+ });
+
+ it('should reinitialize search filters', () => {
+
+ expect(comp.initFilters).toHaveBeenCalledTimes(1);
+
+ refreshFiltersEmitter.next();
+
+ expect(comp.initFilters).toHaveBeenCalledTimes(2);
+ });
+ });
+
});
diff --git a/src/app/shared/search/search-filters/search-filters.component.ts b/src/app/shared/search/search-filters/search-filters.component.ts
index 5daa0f17e0..348af6743d 100644
--- a/src/app/shared/search/search-filters/search-filters.component.ts
+++ b/src/app/shared/search/search-filters/search-filters.component.ts
@@ -1,4 +1,4 @@
-import { Component, Inject, Input, OnInit } from '@angular/core';
+import { Component, Inject, Input, OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
@@ -12,17 +12,19 @@ import { getFirstSucceededRemoteData } from '../../../core/shared/operators';
import { SEARCH_CONFIG_SERVICE } from '../../../+my-dspace-page/my-dspace-page.component';
import { currentPath } from '../../utils/route.utils';
import { Router } from '@angular/router';
+import { hasValue } from '../../empty.util';
@Component({
selector: 'ds-search-filters',
styleUrls: ['./search-filters.component.scss'],
templateUrl: './search-filters.component.html',
+
})
/**
* This component represents the part of the search sidebar that contains filters.
*/
-export class SearchFiltersComponent implements OnInit {
+export class SearchFiltersComponent implements OnInit, OnDestroy {
/**
* An observable containing configuration about which filters are shown and how they are shown
*/
@@ -39,11 +41,18 @@ export class SearchFiltersComponent implements OnInit {
*/
@Input() inPlaceSearch;
+ /**
+ * Emits when the search filters values may be stale, and so they must be refreshed.
+ */
+ @Input() refreshFilters: Observable;
+
/**
* Link to the search page
*/
searchLink: string;
+ subs = [];
+
/**
* Initialize instance variables
* @param {SearchService} searchService
@@ -58,9 +67,12 @@ export class SearchFiltersComponent implements OnInit {
}
ngOnInit(): void {
- this.filters = this.searchConfigService.searchOptions.pipe(
- switchMap((options) => this.searchService.getConfig(options.scope, options.configuration).pipe(getFirstSucceededRemoteData())),
- );
+
+ this.initFilters();
+
+ if (this.refreshFilters) {
+ this.subs.push(this.refreshFilters.subscribe(() => this.initFilters()));
+ }
this.clearParams = this.searchConfigService.getCurrentFrontendFilters().pipe(map((filters) => {
Object.keys(filters).forEach((f) => filters[f] = null);
@@ -69,6 +81,12 @@ export class SearchFiltersComponent implements OnInit {
this.searchLink = this.getSearchLink();
}
+ initFilters() {
+ this.filters = this.searchConfigService.searchOptions.pipe(
+ switchMap((options) => this.searchService.getConfig(options.scope, options.configuration).pipe(getFirstSucceededRemoteData())),
+ );
+ }
+
/**
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
*/
@@ -85,4 +103,12 @@ export class SearchFiltersComponent implements OnInit {
trackUpdate(index, config: SearchFilterConfig) {
return config ? config.name : undefined;
}
+
+ ngOnDestroy() {
+ this.subs.forEach((sub) => {
+ if (hasValue(sub)) {
+ sub.unsubscribe();
+ }
+ });
+ }
}
diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.html b/src/app/shared/search/search-sidebar/search-sidebar.component.html
index 638aed7834..74abeadfd8 100644
--- a/src/app/shared/search/search-sidebar/search-sidebar.component.html
+++ b/src/app/shared/search/search-sidebar/search-sidebar.component.html
@@ -11,7 +11,7 @@
diff --git a/src/app/shared/search/search-sidebar/search-sidebar.component.ts b/src/app/shared/search/search-sidebar/search-sidebar.component.ts
index 42e8a444bc..2060e0f345 100644
--- a/src/app/shared/search/search-sidebar/search-sidebar.component.ts
+++ b/src/app/shared/search/search-sidebar/search-sidebar.component.ts
@@ -1,6 +1,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { SearchConfigurationOption } from '../search-switch-configuration/search-configuration-option.model';
+import { Observable } from 'rxjs';
/**
* This component renders a simple item page.
@@ -44,6 +45,11 @@ export class SearchSidebarComponent {
*/
@Input() inPlaceSearch;
+ /**
+ * Emits when the search filters values may be stale, and so they must be refreshed.
+ */
+ @Input() refreshFilters: Observable;
+
/**
* Emits event when the user clicks a button to open or close the sidebar
*/