diff --git a/src/app/shared/search/search-export-csv/search-export-csv.component.html b/src/app/shared/search/search-export-csv/search-export-csv.component.html index 7bf8704300..8c92ff8fbd 100644 --- a/src/app/shared/search/search-export-csv/search-export-csv.component.html +++ b/src/app/shared/search/search-export-csv/search-export-csv.component.html @@ -1,7 +1,20 @@ + +
+

{{tooltipMsg | translate}}

+
+
+ + +
+

{{tooltipMsg | translate}}

+

{{exportLimitExceededMsg}}

+
+
+ \ No newline at end of file + diff --git a/src/app/shared/search/search-export-csv/search-export-csv.component.spec.ts b/src/app/shared/search/search-export-csv/search-export-csv.component.spec.ts index f75f01afa2..10c42cb812 100644 --- a/src/app/shared/search/search-export-csv/search-export-csv.component.spec.ts +++ b/src/app/shared/search/search-export-csv/search-export-csv.component.spec.ts @@ -2,6 +2,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { of as observableOf } from 'rxjs'; import { TranslateModule } from '@ngx-translate/core'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service'; import { SearchExportCsvComponent } from './search-export-csv.component'; import { ScriptDataService } from '../../../core/data/processes/script-data.service'; @@ -23,6 +24,7 @@ describe('SearchExportCsvComponent', () => { let authorizationDataService: AuthorizationDataService; let notificationsService; let router; + let configurationDataService: jasmine.SpyObj; const process = Object.assign(new Process(), {processId: 5, scriptName: 'metadata-export-search'}); @@ -37,6 +39,10 @@ describe('SearchExportCsvComponent', () => { ] }); + configurationDataService = jasmine.createSpyObj('ConfigurationDataService', { + findByPropertyName: observableOf({ payload: { value: '500' } }), + }); + function initBeforeEachAsync() { scriptDataService = jasmine.createSpyObj('scriptDataService', { scriptWithNameExistsAndCanExecute: observableOf(true), @@ -57,6 +63,7 @@ describe('SearchExportCsvComponent', () => { {provide: AuthorizationDataService, useValue: authorizationDataService}, {provide: NotificationsService, useValue: notificationsService}, {provide: Router, useValue: router}, + { provide: ConfigurationDataService, useValue: configurationDataService }, ] }).compileComponents(); } diff --git a/src/app/shared/search/search-export-csv/search-export-csv.component.ts b/src/app/shared/search/search-export-csv/search-export-csv.component.ts index 27c0e86205..a02547b448 100644 --- a/src/app/shared/search/search-export-csv/search-export-csv.component.ts +++ b/src/app/shared/search/search-export-csv/search-export-csv.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { Observable } from 'rxjs'; import { ScriptDataService } from '../../../core/data/processes/script-data.service'; import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; @@ -14,6 +14,8 @@ import { TranslateService } from '@ngx-translate/core'; import { Router } from '@angular/router'; import { PaginatedSearchOptions } from '../models/paginated-search-options.model'; import { SearchFilter } from '../models/search-filter.model'; +import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; +import { ConfigurationProperty } from '../../../core/shared/configuration-property.model'; @Component({ selector: 'ds-search-export-csv', @@ -23,13 +25,18 @@ import { SearchFilter } from '../models/search-filter.model'; /** * Display a button to export the current search results as csv */ -export class SearchExportCsvComponent implements OnInit { +export class SearchExportCsvComponent implements OnInit, OnChanges { /** * The current configuration of the search */ @Input() searchConfig: PaginatedSearchOptions; + /** + * The total number of items in the search results which can be exported + */ + @Input() total: number; + /** * Observable used to determine whether the button should be shown */ @@ -40,12 +47,18 @@ export class SearchExportCsvComponent implements OnInit { */ tooltipMsg = 'metadata-export-search.tooltip'; + exportLimitExceededKey = 'metadata-export-search.submit.error.limit-exceeded'; + + exportLimitExceededMsg = ''; + + shouldShowWarning$: Observable; + constructor(private scriptDataService: ScriptDataService, private authorizationDataService: AuthorizationDataService, private notificationsService: NotificationsService, private translateService: TranslateService, - private router: Router - ) { + private router: Router, + private configurationService: ConfigurationDataService) { } ngOnInit(): void { @@ -55,6 +68,31 @@ export class SearchExportCsvComponent implements OnInit { map((canExecute: boolean) => canExecute), startWith(false), ); + this.shouldShowWarning$ = this.itemExceeds(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.total) { + this.shouldShowWarning$ = this.itemExceeds(); + } + } + + /** + * Checks if the export limit has been exceeded and updates the tooltip accordingly + */ + private itemExceeds(): Observable { + return this.configurationService.findByPropertyName('bulkedit.export.max.items').pipe( + getFirstCompletedRemoteData(), + map((response: RemoteData) => { + const limit = Number(response.payload?.values?.[0]) || 500; + if (limit < this.total) { + this.exportLimitExceededMsg = this.translateService.instant(this.exportLimitExceededKey, { limit: String(limit) }); + return true; + } else { + return false; + } + }), + ); } /** diff --git a/src/app/shared/search/search-results/search-results.component.html b/src/app/shared/search/search-results/search-results.component.html index c396fce5fb..ef8a69c8a8 100644 --- a/src/app/shared/search/search-results/search-results.component.html +++ b/src/app/shared/search/search-results/search-results.component.html @@ -1,6 +1,7 @@

{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}

- +