mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Merge pull request #873 from atmire/w2p-fix-bitstreams-pagination-on-item-page
Fix bug concerning bistream pagination on the item page
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<ds-metadata-field-wrapper [label]="label | translate">
|
<ds-metadata-field-wrapper [label]="label | translate">
|
||||||
<div *ngVar="(originals$ | async)?.payload as originals">
|
<div *ngVar="(originals$ | async)?.payload as originals">
|
||||||
|
<div *ngIf="hasValuesInBundle(originals)">
|
||||||
<h5 class="simple-view-element-header">{{"item.page.filesection.original.bundle" | translate}}</h5>
|
<h5 class="simple-view-element-header">{{"item.page.filesection.original.bundle" | translate}}</h5>
|
||||||
<ds-pagination *ngIf="originals?.page?.length > 0"
|
<ds-pagination *ngIf="originals?.page?.length > 0"
|
||||||
[hideGear]="true"
|
[hideGear]="true"
|
||||||
@@ -11,7 +12,6 @@
|
|||||||
(pageChange)="switchOriginalPage($event)">
|
(pageChange)="switchOriginalPage($event)">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="file-section row" *ngFor="let file of originals?.page;">
|
<div class="file-section row" *ngFor="let file of originals?.page;">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<dd class="col-md-8">{{file.name}}</dd>
|
<dd class="col-md-8">{{file.name}}</dd>
|
||||||
|
|
||||||
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
|
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
|
||||||
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
|
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
|
||||||
|
|
||||||
|
|
||||||
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
|
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
|
||||||
@@ -41,8 +41,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div *ngVar="(licenses$ | async)?.payload as licenses">
|
<div *ngVar="(licenses$ | async)?.payload as licenses">
|
||||||
|
<div *ngIf="hasValuesInBundle(licenses)">
|
||||||
<h5 class="simple-view-element-header">{{"item.page.filesection.license.bundle" | translate}}</h5>
|
<h5 class="simple-view-element-header">{{"item.page.filesection.license.bundle" | translate}}</h5>
|
||||||
<ds-pagination *ngIf="licenses?.page?.length > 0"
|
<ds-pagination *ngIf="licenses?.page?.length > 0"
|
||||||
[hideGear]="true"
|
[hideGear]="true"
|
||||||
@@ -54,7 +55,6 @@
|
|||||||
(pageChange)="switchLicensePage($event)">
|
(pageChange)="switchLicensePage($event)">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="file-section row" *ngFor="let file of licenses?.page;">
|
<div class="file-section row" *ngFor="let file of licenses?.page;">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
||||||
@@ -65,8 +65,7 @@
|
|||||||
<dd class="col-md-8">{{file.name}}</dd>
|
<dd class="col-md-8">{{file.name}}</dd>
|
||||||
|
|
||||||
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
|
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
|
||||||
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
|
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
|
||||||
|
|
||||||
|
|
||||||
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
|
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
|
||||||
<dd class="col-md-8">{{(file.format | async)?.payload?.description}}</dd>
|
<dd class="col-md-8">{{(file.format | async)?.payload?.description}}</dd>
|
||||||
@@ -84,4 +83,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</ds-metadata-field-wrapper>
|
</ds-metadata-field-wrapper>
|
||||||
|
@@ -14,6 +14,8 @@ import {Bitstream} from '../../../../core/shared/bitstream.model';
|
|||||||
import {of as observableOf} from 'rxjs';
|
import {of as observableOf} from 'rxjs';
|
||||||
import {MockBitstreamFormat1} from '../../../../shared/mocks/item.mock';
|
import {MockBitstreamFormat1} from '../../../../shared/mocks/item.mock';
|
||||||
import {By} from '@angular/platform-browser';
|
import {By} from '@angular/platform-browser';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
|
||||||
|
|
||||||
describe('FullFileSectionComponent', () => {
|
describe('FullFileSectionComponent', () => {
|
||||||
let comp: FullFileSectionComponent;
|
let comp: FullFileSectionComponent;
|
||||||
@@ -61,7 +63,8 @@ describe('FullFileSectionComponent', () => {
|
|||||||
}), BrowserAnimationsModule],
|
}), BrowserAnimationsModule],
|
||||||
declarations: [FullFileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
|
declarations: [FullFileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: BitstreamDataService, useValue: bitstreamDataService}
|
{provide: BitstreamDataService, useValue: bitstreamDataService},
|
||||||
|
{provide: NotificationsService, useValue: new NotificationsServiceStub()}
|
||||||
],
|
],
|
||||||
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
@@ -10,6 +10,10 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina
|
|||||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
import { switchMap } from 'rxjs/operators';
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { hasValue, isEmpty } from '../../../../shared/empty.util';
|
||||||
|
import { tap } from 'rxjs/internal/operators/tap';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders the file section of the item
|
* This component renders the file section of the item
|
||||||
@@ -46,9 +50,11 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
|
|||||||
licenseCurrentPage$ = new BehaviorSubject<number>(1);
|
licenseCurrentPage$ = new BehaviorSubject<number>(1);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
bitstreamDataService: BitstreamDataService
|
bitstreamDataService: BitstreamDataService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translateService: TranslateService
|
||||||
) {
|
) {
|
||||||
super(bitstreamDataService);
|
super(bitstreamDataService, notificationsService, translateService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -62,7 +68,13 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
|
|||||||
'ORIGINAL',
|
'ORIGINAL',
|
||||||
{elementsPerPage: this.pageSize, currentPage: pageNumber},
|
{elementsPerPage: this.pageSize, currentPage: pageNumber},
|
||||||
followLink('format')
|
followLink('format')
|
||||||
))
|
)),
|
||||||
|
tap((rd: RemoteData<PaginatedList<Bitstream>>) => {
|
||||||
|
if (hasValue(rd.error)) {
|
||||||
|
this.notificationsService.error(this.translateService.get('file-section.error.header'), `${rd.error.statusCode} ${rd.error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.licenses$ = this.licenseCurrentPage$.pipe(
|
this.licenses$ = this.licenseCurrentPage$.pipe(
|
||||||
@@ -71,7 +83,13 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
|
|||||||
'LICENSE',
|
'LICENSE',
|
||||||
{elementsPerPage: this.pageSize, currentPage: pageNumber},
|
{elementsPerPage: this.pageSize, currentPage: pageNumber},
|
||||||
followLink('format')
|
followLink('format')
|
||||||
))
|
)),
|
||||||
|
tap((rd: RemoteData<PaginatedList<Bitstream>>) => {
|
||||||
|
if (hasValue(rd.error)) {
|
||||||
|
this.notificationsService.error(this.translateService.get('file-section.error.header'), `${rd.error.statusCode} ${rd.error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -93,4 +111,8 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
|
|||||||
this.licenseOptions.currentPage = page;
|
this.licenseOptions.currentPage = page;
|
||||||
this.licenseCurrentPage$.next(page);
|
this.licenseCurrentPage$.next(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasValuesInBundle(bundle: PaginatedList<Bitstream>) {
|
||||||
|
return hasValue(bundle) && !isEmpty(bundle.page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,8 @@ import {FileSizePipe} from '../../../../shared/utils/file-size-pipe';
|
|||||||
import {PageInfo} from '../../../../core/shared/page-info.model';
|
import {PageInfo} from '../../../../core/shared/page-info.model';
|
||||||
import {MetadataFieldWrapperComponent} from '../../../field-components/metadata-field-wrapper/metadata-field-wrapper.component';
|
import {MetadataFieldWrapperComponent} from '../../../field-components/metadata-field-wrapper/metadata-field-wrapper.component';
|
||||||
import {createPaginatedList} from '../../../../shared/testing/utils.test';
|
import {createPaginatedList} from '../../../../shared/testing/utils.test';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
|
||||||
|
|
||||||
describe('FileSectionComponent', () => {
|
describe('FileSectionComponent', () => {
|
||||||
let comp: FileSectionComponent;
|
let comp: FileSectionComponent;
|
||||||
@@ -62,7 +64,8 @@ describe('FileSectionComponent', () => {
|
|||||||
}), BrowserAnimationsModule],
|
}), BrowserAnimationsModule],
|
||||||
declarations: [FileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
|
declarations: [FileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: BitstreamDataService, useValue: bitstreamDataService}
|
{provide: BitstreamDataService, useValue: bitstreamDataService},
|
||||||
|
{provide: NotificationsService, useValue: new NotificationsServiceStub()}
|
||||||
],
|
],
|
||||||
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
@@ -4,10 +4,12 @@ import { BitstreamDataService } from '../../../../core/data/bitstream-data.servi
|
|||||||
|
|
||||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||||
import { Item } from '../../../../core/shared/item.model';
|
import { Item } from '../../../../core/shared/item.model';
|
||||||
import { filter, takeWhile } from 'rxjs/operators';
|
import { filter, take } from 'rxjs/operators';
|
||||||
import { RemoteData } from '../../../../core/data/remote-data';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
import { hasNoValue, hasValue } from '../../../../shared/empty.util';
|
import { hasValue } from '../../../../shared/empty.util';
|
||||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders the file section of the item
|
* This component renders the file section of the item
|
||||||
@@ -36,7 +38,9 @@ export class FileSectionComponent implements OnInit {
|
|||||||
pageSize = 5;
|
pageSize = 5;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected bitstreamDataService: BitstreamDataService
|
protected bitstreamDataService: BitstreamDataService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected translateService: TranslateService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,14 +62,21 @@ export class FileSectionComponent implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
this.currentPage++;
|
this.currentPage++;
|
||||||
}
|
}
|
||||||
this.bitstreamDataService.findAllByItemAndBundleName(this.item, 'ORIGINAL', { currentPage: this.currentPage, elementsPerPage: this.pageSize }).pipe(
|
this.bitstreamDataService.findAllByItemAndBundleName(this.item, 'ORIGINAL', {
|
||||||
filter((bitstreamsRD: RemoteData<PaginatedList<Bitstream>>) => hasValue(bitstreamsRD)),
|
currentPage: this.currentPage,
|
||||||
takeWhile((bitstreamsRD: RemoteData<PaginatedList<Bitstream>>) => hasNoValue(bitstreamsRD.payload) && hasNoValue(bitstreamsRD.error), true)
|
elementsPerPage: this.pageSize
|
||||||
|
}).pipe(
|
||||||
|
filter((bitstreamsRD: RemoteData<PaginatedList<Bitstream>>) => hasValue(bitstreamsRD) && (hasValue(bitstreamsRD.error) || hasValue(bitstreamsRD.payload))),
|
||||||
|
take(1),
|
||||||
).subscribe((bitstreamsRD: RemoteData<PaginatedList<Bitstream>>) => {
|
).subscribe((bitstreamsRD: RemoteData<PaginatedList<Bitstream>>) => {
|
||||||
|
if (bitstreamsRD.error) {
|
||||||
|
this.notificationsService.error(this.translateService.get('file-section.error.header'), `${bitstreamsRD.error.statusCode} ${bitstreamsRD.error.message}`);
|
||||||
|
} else if (hasValue(bitstreamsRD.payload)) {
|
||||||
const current: Bitstream[] = this.bitstreams$.getValue();
|
const current: Bitstream[] = this.bitstreams$.getValue();
|
||||||
this.bitstreams$.next([...current, ...bitstreamsRD.payload.page]);
|
this.bitstreams$.next([...current, ...bitstreamsRD.payload.page]);
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.isLastPage = this.currentPage === bitstreamsRD.payload.totalPages;
|
this.isLastPage = this.currentPage === bitstreamsRD.payload.totalPages;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,8 @@ import { RestResponse } from '../cache/response.models';
|
|||||||
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||||
import { configureRequest, getResponseFromEntry } from '../shared/operators';
|
import { configureRequest, getResponseFromEntry } from '../shared/operators';
|
||||||
import { combineLatest as observableCombineLatest } from 'rxjs';
|
import { combineLatest as observableCombineLatest } from 'rxjs';
|
||||||
|
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||||
|
import { PageInfo } from '../shared/page-info.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service to retrieve {@link Bitstream}s from the REST API
|
* A service to retrieve {@link Bitstream}s from the REST API
|
||||||
@@ -165,8 +167,10 @@ export class BitstreamDataService extends DataService<Bitstream> {
|
|||||||
public findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
|
public findAllByItemAndBundleName(item: Item, bundleName: string, options?: FindListOptions, ...linksToFollow: Array<FollowLinkConfig<Bitstream>>): Observable<RemoteData<PaginatedList<Bitstream>>> {
|
||||||
return this.bundleService.findByItemAndName(item, bundleName).pipe(
|
return this.bundleService.findByItemAndName(item, bundleName).pipe(
|
||||||
switchMap((bundleRD: RemoteData<Bundle>) => {
|
switchMap((bundleRD: RemoteData<Bundle>) => {
|
||||||
if (hasValue(bundleRD.payload)) {
|
if (bundleRD.hasSucceeded && hasValue(bundleRD.payload)) {
|
||||||
return this.findAllByBundle(bundleRD.payload, options, ...linksToFollow);
|
return this.findAllByBundle(bundleRD.payload, options, ...linksToFollow);
|
||||||
|
} else if (!bundleRD.hasSucceeded && bundleRD.error.statusCode === 404) {
|
||||||
|
return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), []))
|
||||||
} else {
|
} else {
|
||||||
return [bundleRD as any];
|
return [bundleRD as any];
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import { FindListOptions, GetRequest } from './request.models';
|
|||||||
import { RequestService } from './request.service';
|
import { RequestService } from './request.service';
|
||||||
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
import { PaginatedSearchOptions } from '../../shared/search/paginated-search-options.model';
|
||||||
import { Bitstream } from '../shared/bitstream.model';
|
import { Bitstream } from '../shared/bitstream.model';
|
||||||
|
import { RemoteDataError } from './remote-data-error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service to retrieve {@link Bundle}s from the REST API
|
* A service to retrieve {@link Bundle}s from the REST API
|
||||||
@@ -71,6 +72,7 @@ export class BundleDataService extends DataService<Bundle> {
|
|||||||
if (hasValue(rd.payload) && hasValue(rd.payload.page)) {
|
if (hasValue(rd.payload) && hasValue(rd.payload.page)) {
|
||||||
const matchingBundle = rd.payload.page.find((bundle: Bundle) =>
|
const matchingBundle = rd.payload.page.find((bundle: Bundle) =>
|
||||||
bundle.name === bundleName);
|
bundle.name === bundleName);
|
||||||
|
if (hasValue(matchingBundle)) {
|
||||||
return new RemoteData(
|
return new RemoteData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
@@ -78,6 +80,9 @@ export class BundleDataService extends DataService<Bundle> {
|
|||||||
undefined,
|
undefined,
|
||||||
matchingBundle
|
matchingBundle
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return new RemoteData(false, false, false, new RemoteDataError(404, 'Not found', `The bundle with name ${bundleName} was not found.` ))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return rd as any;
|
return rd as any;
|
||||||
}
|
}
|
||||||
|
@@ -1107,6 +1107,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"file-section.error.header": "Error obtaining files for this item",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"footer.copyright": "copyright © 2002-{{ year }}",
|
"footer.copyright": "copyright © 2002-{{ year }}",
|
||||||
|
|
||||||
"footer.link.dspace": "DSpace software",
|
"footer.link.dspace": "DSpace software",
|
||||||
|
Reference in New Issue
Block a user