mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Merge pull request #4530 from atmire/w2p-119612_export-item-limit-7_x
[Port dspace-7_x] UI warning for export item limit
This commit is contained in:
@@ -1,7 +1,20 @@
|
|||||||
|
<ng-template #tipContent>
|
||||||
|
<div class="tooltip-content">
|
||||||
|
<p class="m-0">{{tooltipMsg | translate}}</p>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #tipContentWarning>
|
||||||
|
<div class="tooltip-content">
|
||||||
|
<p class="m-0">{{tooltipMsg | translate}}</p>
|
||||||
|
<p class="m-0 text-warning">{{exportLimitExceededMsg}}</p>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
<button *ngIf="shouldShowButton$ | async"
|
<button *ngIf="shouldShowButton$ | async"
|
||||||
class="export-button btn btn-dark btn-sm"
|
class="export-button btn btn-dark btn-sm"
|
||||||
[ngbTooltip]="tooltipMsg | translate"
|
[ngbTooltip]="(shouldShowWarning$ | async) ? tipContentWarning : tipContent"
|
||||||
(click)="export()"
|
(click)="export()"
|
||||||
[title]="tooltipMsg |translate" [attr.aria-label]="tooltipMsg |translate">
|
[title]="tooltipMsg | translate" [attr.aria-label]="(shouldShowWarning$ | async) ? ((tooltipMsg | translate) + ' ' + exportLimitExceededMsg): (tooltipMsg | translate)">
|
||||||
<i class="fas fa-file-export fa-fw"></i>
|
<i class="fas fa-file-export fa-fw"></i>
|
||||||
</button>
|
</button>
|
@@ -2,6 +2,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
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 { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
|
||||||
import { SearchExportCsvComponent } from './search-export-csv.component';
|
import { SearchExportCsvComponent } from './search-export-csv.component';
|
||||||
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
||||||
@@ -23,6 +24,7 @@ describe('SearchExportCsvComponent', () => {
|
|||||||
let authorizationDataService: AuthorizationDataService;
|
let authorizationDataService: AuthorizationDataService;
|
||||||
let notificationsService;
|
let notificationsService;
|
||||||
let router;
|
let router;
|
||||||
|
let configurationDataService: jasmine.SpyObj<ConfigurationDataService>;
|
||||||
|
|
||||||
const process = Object.assign(new Process(), {processId: 5, scriptName: 'metadata-export-search'});
|
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() {
|
function initBeforeEachAsync() {
|
||||||
scriptDataService = jasmine.createSpyObj('scriptDataService', {
|
scriptDataService = jasmine.createSpyObj('scriptDataService', {
|
||||||
scriptWithNameExistsAndCanExecute: observableOf(true),
|
scriptWithNameExistsAndCanExecute: observableOf(true),
|
||||||
@@ -57,6 +63,7 @@ describe('SearchExportCsvComponent', () => {
|
|||||||
{provide: AuthorizationDataService, useValue: authorizationDataService},
|
{provide: AuthorizationDataService, useValue: authorizationDataService},
|
||||||
{provide: NotificationsService, useValue: notificationsService},
|
{provide: NotificationsService, useValue: notificationsService},
|
||||||
{provide: Router, useValue: router},
|
{provide: Router, useValue: router},
|
||||||
|
{ provide: ConfigurationDataService, useValue: configurationDataService },
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}
|
}
|
||||||
|
@@ -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 { Observable } from 'rxjs';
|
||||||
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
import { ScriptDataService } from '../../../core/data/processes/script-data.service';
|
||||||
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
|
||||||
@@ -14,6 +14,8 @@ import { TranslateService } from '@ngx-translate/core';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { PaginatedSearchOptions } from '../models/paginated-search-options.model';
|
import { PaginatedSearchOptions } from '../models/paginated-search-options.model';
|
||||||
import { SearchFilter } from '../models/search-filter.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({
|
@Component({
|
||||||
selector: 'ds-search-export-csv',
|
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
|
* 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
|
* The current configuration of the search
|
||||||
*/
|
*/
|
||||||
@Input() searchConfig: PaginatedSearchOptions;
|
@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
|
* Observable used to determine whether the button should be shown
|
||||||
*/
|
*/
|
||||||
@@ -40,12 +47,18 @@ export class SearchExportCsvComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
tooltipMsg = 'metadata-export-search.tooltip';
|
tooltipMsg = 'metadata-export-search.tooltip';
|
||||||
|
|
||||||
|
exportLimitExceededKey = 'metadata-export-search.submit.error.limit-exceeded';
|
||||||
|
|
||||||
|
exportLimitExceededMsg = '';
|
||||||
|
|
||||||
|
shouldShowWarning$: Observable<boolean>;
|
||||||
|
|
||||||
constructor(private scriptDataService: ScriptDataService,
|
constructor(private scriptDataService: ScriptDataService,
|
||||||
private authorizationDataService: AuthorizationDataService,
|
private authorizationDataService: AuthorizationDataService,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
) {
|
private configurationService: ConfigurationDataService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -55,6 +68,31 @@ export class SearchExportCsvComponent implements OnInit {
|
|||||||
map((canExecute: boolean) => canExecute),
|
map((canExecute: boolean) => canExecute),
|
||||||
startWith(false),
|
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<boolean> {
|
||||||
|
return this.configurationService.findByPropertyName('bulkedit.export.max.items').pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
map((response: RemoteData<ConfigurationProperty>) => {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<h1 *ngIf="!disableHeader">{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}</h1>
|
<h1 *ngIf="!disableHeader">{{ (configuration ? configuration + '.search.results.head' : 'search.results.head') | translate }}</h1>
|
||||||
<ds-search-export-csv *ngIf="showCsvExport" [searchConfig]="searchConfig"></ds-search-export-csv>
|
<ds-search-export-csv *ngIf="showCsvExport" [total]="searchResults?.payload?.totalElements"
|
||||||
|
[searchConfig]="searchConfig"></ds-search-export-csv>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="searchResults && searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn>
|
<div *ngIf="searchResults && searchResults?.hasSucceeded && !searchResults?.isLoading && searchResults?.payload?.page.length > 0" @fadeIn>
|
||||||
<ds-viewable-collection
|
<ds-viewable-collection
|
||||||
|
@@ -5496,4 +5496,6 @@
|
|||||||
"live-region.ordering.dropped": "{{ itemName }}, dropped at position {{ index }} of {{ length }}.",
|
"live-region.ordering.dropped": "{{ itemName }}, dropped at position {{ index }} of {{ length }}.",
|
||||||
|
|
||||||
"dynamic-form-array.sortable-list.label": "Sortable list",
|
"dynamic-form-array.sortable-list.label": "Sortable list",
|
||||||
|
|
||||||
|
"metadata-export-search.submit.error.limit-exceeded": "Only the first {{limit}} items will be exported",
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user