mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 10:34:15 +00:00
68346: PaginatedDragAndDropBitstreamList component and refactoring item-edit-bitstream-bundle using this new component ; removed pagination-drag-and-drop
This commit is contained in:
@@ -27,6 +27,7 @@ import { ItemEditBitstreamBundleComponent } from './item-bitstreams/item-edit-bi
|
||||
import { BundleDataService } from '../../core/data/bundle-data.service';
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component';
|
||||
import { PaginatedDragAndDropBitstreamListComponent } from './item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Item page administrator functionality
|
||||
@@ -57,6 +58,7 @@ import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edi
|
||||
EditInPlaceFieldComponent,
|
||||
ItemEditBitstreamComponent,
|
||||
ItemEditBitstreamBundleComponent,
|
||||
PaginatedDragAndDropBitstreamListComponent,
|
||||
EditInPlaceFieldComponent,
|
||||
EditRelationshipComponent,
|
||||
EditRelationshipListComponent,
|
||||
|
@@ -17,29 +17,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ds-pagination-drag-and-drop [paginationOptions]="bitstreamsOptions"
|
||||
[paginatedList]="(bitstreamsRD$ | async)?.payload"
|
||||
[hideGear]="true"
|
||||
[hidePaginationDetail]="true"
|
||||
[disableRouteParameterUpdate]="true"
|
||||
(pageChange)="switchPage($event)">
|
||||
<div [id]="bundle.id" class="bundle-bitstreams-list"
|
||||
[ngClass]="{'mb-3': (bitstreamsRD$ | async)?.payload?.totalElements > batchSize}"
|
||||
*ngVar="((updates$ | async) | dsObjectValues) as updateValues" cdkDropList (cdkDropListDropped)="drop($event)">
|
||||
<div class="row bitstream-row" *ngFor="let updateValue of updateValues" cdkDrag
|
||||
[ngClass]="{
|
||||
'table-warning': updateValue.changeType === 0,
|
||||
'table-danger': updateValue.changeType === 2,
|
||||
'table-success': updateValue.changeType === 1,
|
||||
'bg-white': updateValue.changeType === undefined
|
||||
}">
|
||||
<ds-item-edit-bitstream [fieldUpdate]="updateValue"
|
||||
[bundleUrl]="bundle.self">
|
||||
<div class="d-flex align-items-center" slot="drag-handle" cdkDragHandle>
|
||||
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
|
||||
</div>
|
||||
</ds-item-edit-bitstream>
|
||||
</div>
|
||||
</div>
|
||||
</ds-pagination-drag-and-drop>
|
||||
<ds-paginated-drag-and-drop-bitstream-list [bundle]="bundle"></ds-paginated-drag-and-drop-bitstream-list>
|
||||
</ng-template>
|
||||
|
@@ -7,7 +7,7 @@ import { toBitstreamsArray } from '../../../../core/shared/item-bitstreams-utils
|
||||
import { map, switchMap, take, tap } from 'rxjs/operators';
|
||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
||||
import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||
import { BundleDataService } from '../../../../core/data/bundle-data.service';
|
||||
@@ -42,85 +42,10 @@ export class ItemEditBitstreamBundleComponent implements OnInit {
|
||||
*/
|
||||
@Input() item: Item;
|
||||
|
||||
/**
|
||||
* The bitstreams within this bundle retrieved from the REST API
|
||||
*/
|
||||
bitstreamsRD$: Observable<RemoteData<PaginatedList<Bitstream>>>;
|
||||
|
||||
/**
|
||||
* The updates to the current bundle
|
||||
*/
|
||||
updates$: Observable<FieldUpdates>;
|
||||
|
||||
/**
|
||||
* The amount of one bitstreams one "batch" resembles
|
||||
* The user is able to increase the amount of bitstreams displayed per bundle by this batch size until all are shown
|
||||
*/
|
||||
batchSize = 2;
|
||||
|
||||
/**
|
||||
* The page options to use for fetching the bitstreams
|
||||
*/
|
||||
bitstreamsOptions = Object.assign(new PaginationComponentOptions(),{
|
||||
id: 'bitstreams-pagination-options',
|
||||
currentPage: 1,
|
||||
pageSize: this.batchSize
|
||||
});
|
||||
|
||||
/**
|
||||
* The current page we're displaying for this bundle
|
||||
*/
|
||||
currentPage$ = new BehaviorSubject<number>(1);
|
||||
|
||||
/**
|
||||
* A list of pages that have been initialized in the field-update store
|
||||
*/
|
||||
initializedPages: number[] = [];
|
||||
|
||||
constructor(private objectUpdatesService: ObjectUpdatesService,
|
||||
private bundleService: BundleDataService,
|
||||
private viewContainerRef: ViewContainerRef) {
|
||||
constructor(private viewContainerRef: ViewContainerRef) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.bitstreamsRD$ = this.currentPage$.pipe(
|
||||
switchMap((page: number) => this.bundleService.getBitstreams(this.bundle.id,
|
||||
new PaginatedSearchOptions({pagination: Object.assign({}, this.bitstreamsOptions, { currentPage: page })})))
|
||||
);
|
||||
this.updates$ = this.bitstreamsRD$.pipe(
|
||||
toBitstreamsArray(),
|
||||
tap((bitstreams: Bitstream[]) => {
|
||||
// Pages in the field-update store are indexed starting at 0 (because they're stored in an array of pages)
|
||||
const updatesPage = this.currentPage$.value - 1;
|
||||
if (isEmpty(this.initializedPages)) {
|
||||
// No updates have been initialized yet for this bundle, initialize the first page
|
||||
this.objectUpdatesService.initializeWithCustomOrder(this.bundle.self, bitstreams, new Date(), this.batchSize, updatesPage);
|
||||
this.initializedPages.push(updatesPage);
|
||||
} else if (this.initializedPages.indexOf(updatesPage) < 0) {
|
||||
// Updates were initialized for this bundle, but not the page we're on. Add the current page to the field-update store for this bundle
|
||||
this.objectUpdatesService.addPageToCustomOrder(this.bundle.self, bitstreams, updatesPage);
|
||||
this.initializedPages.push(updatesPage);
|
||||
}
|
||||
}),
|
||||
switchMap((bitstreams: Bitstream[]) => this.objectUpdatesService.getFieldUpdatesByCustomOrder(this.bundle.self, bitstreams, this.currentPage$.value - 1))
|
||||
);
|
||||
|
||||
this.viewContainerRef.createEmbeddedView(this.bundleView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current page
|
||||
* @param page
|
||||
*/
|
||||
switchPage(page: number) {
|
||||
this.currentPage$.next(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitstream was moved, send updates to the store
|
||||
* @param event
|
||||
*/
|
||||
drop(event: CdkDragDrop<any>) {
|
||||
this.objectUpdatesService.saveMoveFieldUpdate(this.bundle.self, event.previousIndex, event.currentIndex, this.currentPage$.value - 1, this.currentPage$.value - 1);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
<ds-pagination *ngIf="(objectsRD$ | async)?.payload"
|
||||
[hideGear]="true"
|
||||
[hidePagerWhenSinglePage]="true"
|
||||
[hidePaginationDetail]="true"
|
||||
[paginationOptions]="options"
|
||||
[pageInfoState]="(objectsRD$ | async)?.payload"
|
||||
[collectionSize]="(objectsRD$ | async)?.payload?.totalElements"
|
||||
[disableRouteParameterUpdate]="true"
|
||||
(pageChange)="switchPage($event)">
|
||||
<div [id]="bundle.id" class="bundle-bitstreams-list"
|
||||
[ngClass]="{'mb-3': (objectsRD$ | async)?.payload?.totalElements > pageSize}"
|
||||
*ngVar="((updates$ | async) | dsObjectValues) as updateValues" cdkDropList (cdkDropListDropped)="drop($event)">
|
||||
<div class="row bitstream-row" *ngFor="let updateValue of updateValues" cdkDrag (cdkDragStarted)="dragStarted($event)"
|
||||
[ngClass]="{
|
||||
'table-warning': updateValue.changeType === 0,
|
||||
'table-danger': updateValue.changeType === 2,
|
||||
'table-success': updateValue.changeType === 1,
|
||||
'bg-white': updateValue.changeType === undefined
|
||||
}">
|
||||
<ds-item-edit-bitstream [fieldUpdate]="updateValue"
|
||||
[bundleUrl]="bundle.self">
|
||||
<div class="d-flex align-items-center" slot="drag-handle" cdkDragHandle>
|
||||
<ds-item-edit-bitstream-drag-handle></ds-item-edit-bitstream-drag-handle>
|
||||
</div>
|
||||
</ds-item-edit-bitstream>
|
||||
</div>
|
||||
</div>
|
||||
</ds-pagination>
|
@@ -0,0 +1,40 @@
|
||||
import { AbstractPaginatedDragAndDropListComponent } from '../../../../../shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Bundle } from '../../../../../core/shared/bundle.model';
|
||||
import { Bitstream } from '../../../../../core/shared/bitstream.model';
|
||||
import { ObjectUpdatesService } from '../../../../../core/data/object-updates/object-updates.service';
|
||||
import { BundleDataService } from '../../../../../core/data/bundle-data.service';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-paginated-drag-and-drop-bitstream-list',
|
||||
styleUrls: ['../../item-bitstreams.component.scss'],
|
||||
templateUrl: './paginated-drag-and-drop-bitstream-list.component.html',
|
||||
})
|
||||
export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginatedDragAndDropListComponent<Bitstream> implements OnInit {
|
||||
/**
|
||||
* The bundle to display bitstreams for
|
||||
*/
|
||||
@Input() bundle: Bundle;
|
||||
|
||||
constructor(protected objectUpdatesService: ObjectUpdatesService,
|
||||
protected bundleService: BundleDataService) {
|
||||
super(objectUpdatesService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
initializeObjectsRD(): void {
|
||||
this.objectsRD$ = this.currentPage$.pipe(
|
||||
switchMap((page: number) => this.bundleService.getBitstreams(this.bundle.id,
|
||||
new PaginatedSearchOptions({pagination: Object.assign({}, this.options, { currentPage: page })})))
|
||||
);
|
||||
}
|
||||
|
||||
initializeURL(): void {
|
||||
this.url = this.bundle.self;
|
||||
}
|
||||
}
|
@@ -137,3 +137,13 @@ export const getFirstSucceededRemoteDataPayload = () =>
|
||||
hasValueOperator(),
|
||||
take(1)
|
||||
);
|
||||
|
||||
/**
|
||||
* Operator for turning the current page of bitstreams into an array
|
||||
*/
|
||||
export const paginatedListToArray = () =>
|
||||
<T extends DSpaceObject>(source: Observable<RemoteData<PaginatedList<T>>>): Observable<T[]> =>
|
||||
source.pipe(
|
||||
hasValueOperator(),
|
||||
map((objectRD: RemoteData<PaginatedList<T>>) => objectRD.payload.page.filter((object: T) => hasValue(object)))
|
||||
);
|
||||
|
@@ -0,0 +1,124 @@
|
||||
import { FieldUpdates } from '../../core/data/object-updates/object-updates.reducer';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||
import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service';
|
||||
import { switchMap, tap } from 'rxjs/operators';
|
||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||
import { isEmpty } from '../empty.util';
|
||||
import { paginatedListToArray } from '../../core/shared/operators';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop';
|
||||
|
||||
export abstract class AbstractPaginatedDragAndDropListComponent<T extends DSpaceObject> {
|
||||
/**
|
||||
* The URL to use for accessing the object updates from this list
|
||||
*/
|
||||
url: string;
|
||||
|
||||
/**
|
||||
* The objects to retrieve data for and transform into field updates
|
||||
*/
|
||||
objectsRD$: Observable<RemoteData<PaginatedList<T>>>;
|
||||
|
||||
/**
|
||||
* The updates to the current list
|
||||
*/
|
||||
updates$: Observable<FieldUpdates>;
|
||||
|
||||
/**
|
||||
* The amount of objects to display per page
|
||||
*/
|
||||
pageSize = 2;
|
||||
|
||||
/**
|
||||
* The page options to use for fetching the objects
|
||||
* Start at page 1 and always use the set page size
|
||||
*/
|
||||
options = Object.assign(new PaginationComponentOptions(),{
|
||||
id: 'paginated-drag-and-drop-options',
|
||||
currentPage: 1,
|
||||
pageSize: this.pageSize
|
||||
});
|
||||
|
||||
/**
|
||||
* The current page being displayed
|
||||
*/
|
||||
currentPage$ = new BehaviorSubject<number>(1);
|
||||
|
||||
/**
|
||||
* The last page we were on when we started dragging an item
|
||||
* This is used to keep track of the original page the drag started from
|
||||
*/
|
||||
lastPage$ = new BehaviorSubject<number>(1);
|
||||
|
||||
/**
|
||||
* A list of pages that have been initialized in the field-update store
|
||||
*/
|
||||
initializedPages: number[] = [];
|
||||
|
||||
protected constructor(protected objectUpdatesService: ObjectUpdatesService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.initializeObjectsRD();
|
||||
this.initializeURL();
|
||||
this.initializeUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite this method to define how the list of objects is initialized and updated
|
||||
*/
|
||||
abstract initializeObjectsRD(): void;
|
||||
|
||||
/**
|
||||
* Overwrite this method to define how the URL is set
|
||||
*/
|
||||
abstract initializeURL(): void;
|
||||
|
||||
/**
|
||||
* Initialize the field-updates in the store
|
||||
* This method ensures (new) pages displayed are automatically added to the field-update store when the objectsRD updates
|
||||
*/
|
||||
initializeUpdates(): void {
|
||||
this.updates$ = this.objectsRD$.pipe(
|
||||
paginatedListToArray(),
|
||||
tap((objects: DSpaceObject[]) => {
|
||||
// Pages in the field-update store are indexed starting at 0 (because they're stored in an array of pages)
|
||||
const updatesPage = this.currentPage$.value - 1;
|
||||
if (isEmpty(this.initializedPages)) {
|
||||
// No updates have been initialized yet for this list, initialize the first page
|
||||
this.objectUpdatesService.initializeWithCustomOrder(this.url, objects, new Date(), this.pageSize, updatesPage);
|
||||
this.initializedPages.push(updatesPage);
|
||||
} else if (this.initializedPages.indexOf(updatesPage) < 0) {
|
||||
// Updates were initialized for this list, but not the page we're on. Add the current page to the field-update store for this list
|
||||
this.objectUpdatesService.addPageToCustomOrder(this.url, objects, updatesPage);
|
||||
this.initializedPages.push(updatesPage);
|
||||
}
|
||||
}),
|
||||
switchMap((bitstreams: Bitstream[]) => this.objectUpdatesService.getFieldUpdatesByCustomOrder(this.url, bitstreams, this.currentPage$.value - 1))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current page
|
||||
* @param page
|
||||
*/
|
||||
switchPage(page: number) {
|
||||
this.currentPage$.next(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bitstream was moved, send updates to the store
|
||||
* @param event
|
||||
*/
|
||||
drop(event: CdkDragDrop<any>) {
|
||||
this.objectUpdatesService.saveMoveFieldUpdate(this.url, event.previousIndex, event.currentIndex, this.lastPage$.value - 1, this.currentPage$.value - 1);
|
||||
}
|
||||
|
||||
dragStarted(event: CdkDragStart) {
|
||||
this.lastPage$.next(this.currentPage$.value);
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
<ds-pagination *ngIf="paginatedList"
|
||||
[hideGear]="hideGear"
|
||||
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
||||
[hidePaginationDetail]="hidePaginationDetail"
|
||||
[paginationOptions]="paginationOptions"
|
||||
[pageInfoState]="paginatedList"
|
||||
[collectionSize]="paginatedList?.totalElements"
|
||||
[disableRouteParameterUpdate]="disableRouteParameterUpdate"
|
||||
(pageChange)="switchPage($event)">
|
||||
<ng-content></ng-content>
|
||||
</ds-pagination>
|
@@ -1,55 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
||||
import { PaginatedList } from '../../core/data/paginated-list';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-pagination-drag-and-drop',
|
||||
templateUrl: './pagination-drag-and-drop.component.html',
|
||||
})
|
||||
export class PaginationDragAndDropComponent {
|
||||
/**
|
||||
* Configuration for the NgbPagination component.
|
||||
*/
|
||||
@Input() paginationOptions: PaginationComponentOptions;
|
||||
|
||||
/**
|
||||
* The paginated list being displayed
|
||||
*/
|
||||
@Input() paginatedList: PaginatedList<any>;
|
||||
|
||||
/**
|
||||
* Option for hiding the pagination detail
|
||||
*/
|
||||
@Input() public hidePaginationDetail = false;
|
||||
|
||||
/**
|
||||
* Option for hiding the gear
|
||||
*/
|
||||
@Input() public hideGear = false;
|
||||
|
||||
/**
|
||||
* Option for hiding the pager when there is less than 2 pages
|
||||
*/
|
||||
@Input() public hidePagerWhenSinglePage = true;
|
||||
|
||||
/**
|
||||
* Option for disabling updating and reading route parameters on pagination changes
|
||||
* In other words, changing pagination won't add or update the url parameters on the current page, and the url
|
||||
* parameters won't affect the pagination of this component
|
||||
*/
|
||||
@Input() public disableRouteParameterUpdate = false;
|
||||
|
||||
/**
|
||||
* An event fired when the page is changed.
|
||||
* Event's payload equals to the newly selected page.
|
||||
*/
|
||||
@Output() pageChange: EventEmitter<number> = new EventEmitter<number>();
|
||||
|
||||
/**
|
||||
* Switch to a different page
|
||||
* @param page Page to switch to
|
||||
*/
|
||||
switchPage(page: number) {
|
||||
this.pageChange.emit(page);
|
||||
}
|
||||
}
|
@@ -178,7 +178,6 @@ import { ImportableListItemControlComponent } from './object-collection/shared/i
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component';
|
||||
import { CustomSwitchComponent } from './form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component';
|
||||
import { PaginationDragAndDropComponent } from './pagination-drag-and-drop/pagination-drag-and-drop.component';
|
||||
|
||||
const MODULES = [
|
||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||
@@ -264,7 +263,6 @@ const COMPONENTS = [
|
||||
AbstractListableElementComponent,
|
||||
ObjectCollectionComponent,
|
||||
PaginationComponent,
|
||||
PaginationDragAndDropComponent,
|
||||
SearchFormComponent,
|
||||
PageWithSidebarComponent,
|
||||
SidebarDropdownComponent,
|
||||
|
Reference in New Issue
Block a user