mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-3930] fix infinite pagination (#4275)
* refactoring infinite pagination * fix lint * fix import reuqest pagination from core * fix failing unit test
This commit is contained in:
@@ -39,6 +39,7 @@ Opens a Content [`Node`](https://github.com/Alfresco/alfresco-js-api/blob/develo
|
|||||||
| isSelectionValid | `ValidationFunction` | defaultValidation | Function used to decide if the selected node has permission to be selected. Default value is a function that always returns true. |
|
| isSelectionValid | `ValidationFunction` | defaultValidation | Function used to decide if the selected node has permission to be selected. Default value is a function that always returns true. |
|
||||||
| pageSize | `number` | | Number of items shown per page in the list. |
|
| pageSize | `number` | | Number of items shown per page in the list. |
|
||||||
| rowFilter | `RowFilter` | null | Custom row filter function. See the [Document List component](document-list.component.md#custom-row-filter) for more information. |
|
| rowFilter | `RowFilter` | null | Custom row filter function. See the [Document List component](document-list.component.md#custom-row-filter) for more information. |
|
||||||
|
| where | `string` | `null` | Custom where filter function. See the [Document List component](document-list.component.md) for more information. |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@ export interface ContentNodeSelectorComponentData {
|
|||||||
dropdownHideMyFiles?: boolean;
|
dropdownHideMyFiles?: boolean;
|
||||||
dropdownSiteList?: SitePaging;
|
dropdownSiteList?: SitePaging;
|
||||||
rowFilter?: any;
|
rowFilter?: any;
|
||||||
|
where?: string;
|
||||||
imageResolver?: any;
|
imageResolver?: any;
|
||||||
isSelectionValid?: (entry: Node) => boolean;
|
isSelectionValid?: (entry: Node) => boolean;
|
||||||
breadcrumbTransform?: (node) => any;
|
breadcrumbTransform?: (node) => any;
|
||||||
@@ -55,6 +56,7 @@ The properties are described in the table below:
|
|||||||
| dropdownHideMyFiles | `boolean` | `false` | Hide the "My Files" option added to the site list by default. See the [Sites Dropdown component](sites-dropdown.component.md) for more information. |
|
| dropdownHideMyFiles | `boolean` | `false` | Hide the "My Files" option added to the site list by default. See the [Sites Dropdown component](sites-dropdown.component.md) for more information. |
|
||||||
| dropdownSiteList | [`SitePaging`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/SitePaging.md) | `null` | Custom site for site dropdown same as siteList. See the [Sites Dropdown component](sites-dropdown.component.md) for more information. |
|
| dropdownSiteList | [`SitePaging`](https://github.com/Alfresco/alfresco-js-api/blob/master/src/alfresco-core-rest-api/docs/SitePaging.md) | `null` | Custom site for site dropdown same as siteList. See the [Sites Dropdown component](sites-dropdown.component.md) for more information. |
|
||||||
| rowFilter | [`RowFilter`](../../lib/content-services/document-list/data/row-filter.model.ts) | `null` | Custom row filter function. See the [Document List component](document-list.component.md#custom-row-filter) for more information. |
|
| rowFilter | [`RowFilter`](../../lib/content-services/document-list/data/row-filter.model.ts) | `null` | Custom row filter function. See the [Document List component](document-list.component.md#custom-row-filter) for more information. |
|
||||||
|
| where | `string` | `null` | Custom where filter function. See the [Document List component](document-list.component.md) for more information. |
|
||||||
| imageResolver | [`ImageResolver`](../../lib/content-services/document-list/data/image-resolver.model.ts) | `null` | Custom image resolver function. See the [Document List component](document-list.component.md#custom-row-filter) for more information. |
|
| imageResolver | [`ImageResolver`](../../lib/content-services/document-list/data/image-resolver.model.ts) | `null` | Custom image resolver function. See the [Document List component](document-list.component.md#custom-row-filter) for more information. |
|
||||||
| pageSize | `number` | | Number of items shown per page in the list. |
|
| pageSize | `number` | | Number of items shown per page in the list. |
|
||||||
| isSelectionValid | [`ValidationFunction`](../../lib/content-services/content-node-selector/content-node-selector-panel.component.ts) | `defaultValidation` | Function used to decide if the selected node has permission to be selected. Default value is a function that always returns true. |
|
| isSelectionValid | [`ValidationFunction`](../../lib/content-services/content-node-selector/content-node-selector-panel.component.ts) | `defaultValidation` | Function used to decide if the selected node has permission to be selected. Default value is a function that always returns true. |
|
||||||
|
@@ -66,6 +66,7 @@ Displays the documents from a repository.
|
|||||||
| emptyFolderImageUrl | `string` | | Custom image for empty folder. Default value: './assets/images/empty_doc_lib.svg' |
|
| emptyFolderImageUrl | `string` | | Custom image for empty folder. Default value: './assets/images/empty_doc_lib.svg' |
|
||||||
| imageResolver | `any \| null` | null | Custom image resolver |
|
| imageResolver | `any \| null` | null | Custom image resolver |
|
||||||
| includeFields | `string[]` | | Include additional information about the node in the server request. For example: association, isLink, isLocked and others. |
|
| includeFields | `string[]` | | Include additional information about the node in the server request. For example: association, isLink, isLocked and others. |
|
||||||
|
| where | `string` | | filter the Node list using the where condition of the rest api for example (isFolder=true) see the rest api documentation for more information. |
|
||||||
| loading | `boolean` | false | Toggles the loading state and animated spinners for the component. Used in combination with `navigate=false` to perform custom navigation and loading state indication. |
|
| loading | `boolean` | false | Toggles the loading state and animated spinners for the component. Used in combination with `navigate=false` to perform custom navigation and loading state indication. |
|
||||||
| locationFormat | `string` | "/" | The default route for all the location-based columns (if declared). |
|
| locationFormat | `string` | "/" | The default route for all the location-based columns (if declared). |
|
||||||
| maxItems | `number` | | Default value is stored into user preference settings use it only if you are not using the pagination |
|
| maxItems | `number` | | Default value is stored into user preference settings use it only if you are not using the pagination |
|
||||||
|
@@ -143,7 +143,7 @@ export class ContentNodeDialogService {
|
|||||||
actionName: action,
|
actionName: action,
|
||||||
currentFolderId: contentEntry.parentId,
|
currentFolderId: contentEntry.parentId,
|
||||||
imageResolver: this.imageResolver.bind(this),
|
imageResolver: this.imageResolver.bind(this),
|
||||||
rowFilter: this.rowFilter.bind(this, contentEntry.id),
|
where: '(isFolder=true)',
|
||||||
isSelectionValid: this.isCopyMoveSelectionValid.bind(this),
|
isSelectionValid: this.isCopyMoveSelectionValid.bind(this),
|
||||||
excludeSiteContent: excludeSiteContent || ContentNodeDialogService.nonDocumentSiteContent,
|
excludeSiteContent: excludeSiteContent || ContentNodeDialogService.nonDocumentSiteContent,
|
||||||
select: select
|
select: select
|
||||||
@@ -186,7 +186,7 @@ export class ContentNodeDialogService {
|
|||||||
currentFolderId: contentEntry.id,
|
currentFolderId: contentEntry.id,
|
||||||
imageResolver: this.imageResolver.bind(this),
|
imageResolver: this.imageResolver.bind(this),
|
||||||
isSelectionValid: this.hasPermissionOnNodeFolder.bind(this),
|
isSelectionValid: this.hasPermissionOnNodeFolder.bind(this),
|
||||||
rowFilter: this.rowFilter.bind(this, contentEntry.id),
|
where: '(isFolder=true)',
|
||||||
select: select
|
select: select
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -232,16 +232,6 @@ export class ContentNodeDialogService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private rowFilter(currentNodeId: string, row: ShareDataRow): boolean {
|
|
||||||
const node: Node = row.node.entry;
|
|
||||||
|
|
||||||
if (node.id === currentNodeId || node.isFile) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private isNodeFile(entry: Node): boolean {
|
private isNodeFile(entry: Node): boolean {
|
||||||
return entry.isFile;
|
return entry.isFile;
|
||||||
}
|
}
|
||||||
|
@@ -56,7 +56,7 @@
|
|||||||
[adf-highlight]="searchTerm"
|
[adf-highlight]="searchTerm"
|
||||||
adf-highlight-selector=".adf-name-location-cell-name"
|
adf-highlight-selector=".adf-name-location-cell-name"
|
||||||
[showHeader]="false"
|
[showHeader]="false"
|
||||||
[node]="nodes"
|
[node]="nodePaging"
|
||||||
[maxItems]="pageSize"
|
[maxItems]="pageSize"
|
||||||
[rowFilter]="_rowFilter"
|
[rowFilter]="_rowFilter"
|
||||||
[imageResolver]="imageResolver"
|
[imageResolver]="imageResolver"
|
||||||
@@ -65,6 +65,7 @@
|
|||||||
[contextMenuActions]="false"
|
[contextMenuActions]="false"
|
||||||
[contentActions]="false"
|
[contentActions]="false"
|
||||||
[allowDropFiles]="false"
|
[allowDropFiles]="false"
|
||||||
|
[where]="where"
|
||||||
(folderChange)="onFolderChange()"
|
(folderChange)="onFolderChange()"
|
||||||
(ready)="onFolderLoaded()"
|
(ready)="onFolderLoaded()"
|
||||||
(node-dblclick)="onNodeDoubleClick($event)"
|
(node-dblclick)="onNodeDoubleClick($event)"
|
||||||
|
@@ -517,7 +517,7 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
|
|
||||||
it('should clear the search field, nodes and chosenNode when clicking on the X (clear) icon', () => {
|
it('should clear the search field, nodes and chosenNode when clicking on the X (clear) icon', () => {
|
||||||
component.chosenNode = <Node> {};
|
component.chosenNode = <Node> {};
|
||||||
component.nodes = {
|
component.nodePaging = {
|
||||||
list: {
|
list: {
|
||||||
entries: [{ entry: component.chosenNode }]
|
entries: [{ entry: component.chosenNode }]
|
||||||
}
|
}
|
||||||
@@ -528,7 +528,7 @@ describe('ContentNodeSelectorComponent', () => {
|
|||||||
component.clear();
|
component.clear();
|
||||||
|
|
||||||
expect(component.searchTerm).toBe('');
|
expect(component.searchTerm).toBe('');
|
||||||
expect(component.nodes).toEqual(null);
|
expect(component.nodePaging).toEqual(null);
|
||||||
expect(component.chosenNode).toBeNull();
|
expect(component.chosenNode).toBeNull();
|
||||||
expect(component.showingSearchResults).toBeFalsy();
|
expect(component.showingSearchResults).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
@@ -19,7 +19,7 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsul
|
|||||||
import { AlfrescoApiService, HighlightDirective, UserPreferencesService, PaginationModel } from '@alfresco/adf-core';
|
import { AlfrescoApiService, HighlightDirective, UserPreferencesService, PaginationModel } from '@alfresco/adf-core';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { Node, NodePaging, Pagination, SiteEntry, SitePaging } from '@alfresco/js-api';
|
import { Node, NodePaging, Pagination, SiteEntry, SitePaging } from '@alfresco/js-api';
|
||||||
import { DocumentListComponent, PaginationStrategy } from '../document-list/components/document-list.component';
|
import { DocumentListComponent } from '../document-list/components/document-list.component';
|
||||||
import { RowFilter } from '../document-list/data/row-filter.model';
|
import { RowFilter } from '../document-list/data/row-filter.model';
|
||||||
import { ImageResolver } from '../document-list/data/image-resolver.model';
|
import { ImageResolver } from '../document-list/data/image-resolver.model';
|
||||||
import { ContentNodeSelectorService } from './content-node-selector.service';
|
import { ContentNodeSelectorService } from './content-node-selector.service';
|
||||||
@@ -62,6 +62,13 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
|
|
||||||
_rowFilter: RowFilter = defaultValidation;
|
_rowFilter: RowFilter = defaultValidation;
|
||||||
|
|
||||||
|
/** Custom where filter function. See the
|
||||||
|
* [Document List component](document-list.component.md)
|
||||||
|
* for more information.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
where: string;
|
||||||
|
|
||||||
/** Custom row filter function. See the
|
/** Custom row filter function. See the
|
||||||
* [Document List component](document-list.component.md#custom-row-filter)
|
* [Document List component](document-list.component.md#custom-row-filter)
|
||||||
* for more information.
|
* for more information.
|
||||||
@@ -125,7 +132,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
@ViewChild(HighlightDirective)
|
@ViewChild(HighlightDirective)
|
||||||
highlighter: HighlightDirective;
|
highlighter: HighlightDirective;
|
||||||
|
|
||||||
nodes: NodePaging | null = null;
|
nodePaging: NodePaging | null = null;
|
||||||
siteId: null | string;
|
siteId: null | string;
|
||||||
searchTerm: string = '';
|
searchTerm: string = '';
|
||||||
showingSearchResults: boolean = false;
|
showingSearchResults: boolean = false;
|
||||||
@@ -133,7 +140,6 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
inDialog: boolean = false;
|
inDialog: boolean = false;
|
||||||
_chosenNode: Node = null;
|
_chosenNode: Node = null;
|
||||||
folderIdToShow: string | null = null;
|
folderIdToShow: string | null = null;
|
||||||
paginationStrategy: PaginationStrategy = PaginationStrategy.Infinite;
|
|
||||||
pagination: BehaviorSubject<PaginationModel>;
|
pagination: BehaviorSubject<PaginationModel>;
|
||||||
|
|
||||||
skipCount: number = 0;
|
skipCount: number = 0;
|
||||||
@@ -255,7 +261,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
clearSearch() {
|
clearSearch() {
|
||||||
this.searchTerm = '';
|
this.searchTerm = '';
|
||||||
this.nodes = null;
|
this.nodePaging = null;
|
||||||
this.skipCount = 0;
|
this.skipCount = 0;
|
||||||
this.chosenNode = null;
|
this.chosenNode = null;
|
||||||
this.showingSearchResults = false;
|
this.showingSearchResults = false;
|
||||||
@@ -276,7 +282,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
* Load the first page of a new search result
|
* Load the first page of a new search result
|
||||||
*/
|
*/
|
||||||
private startNewSearch(): void {
|
private startNewSearch(): void {
|
||||||
this.nodes = null;
|
this.nodePaging = null;
|
||||||
this.skipCount = 0;
|
this.skipCount = 0;
|
||||||
this.chosenNode = null;
|
this.chosenNode = null;
|
||||||
this.folderIdToShow = null;
|
this.folderIdToShow = null;
|
||||||
@@ -313,14 +319,7 @@ export class ContentNodeSelectorPanelComponent implements OnInit {
|
|||||||
this.showingSearchResults = true;
|
this.showingSearchResults = true;
|
||||||
this.loadingSearchResults = false;
|
this.loadingSearchResults = false;
|
||||||
|
|
||||||
// DocumentList hack, since data displaying for preloaded nodes is a little bit messy there
|
this.nodePaging = nodePaging;
|
||||||
if (!this.nodes) {
|
|
||||||
this.nodes = nodePaging;
|
|
||||||
} else {
|
|
||||||
this.documentList.data.loadPage(nodePaging, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pagination.next(nodePaging.list.pagination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -25,6 +25,7 @@ export interface ContentNodeSelectorComponentData {
|
|||||||
dropdownHideMyFiles?: boolean;
|
dropdownHideMyFiles?: boolean;
|
||||||
dropdownSiteList?: SitePaging;
|
dropdownSiteList?: SitePaging;
|
||||||
rowFilter?: any;
|
rowFilter?: any;
|
||||||
|
where?: string;
|
||||||
imageResolver?: any;
|
imageResolver?: any;
|
||||||
isSelectionValid?: (entry: Node) => boolean;
|
isSelectionValid?: (entry: Node) => boolean;
|
||||||
breadcrumbTransform?: (node) => any;
|
breadcrumbTransform?: (node) => any;
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
[isSelectionValid]="data?.isSelectionValid"
|
[isSelectionValid]="data?.isSelectionValid"
|
||||||
[breadcrumbTransform]="data?.breadcrumbTransform"
|
[breadcrumbTransform]="data?.breadcrumbTransform"
|
||||||
[excludeSiteContent]="data?.excludeSiteContent"
|
[excludeSiteContent]="data?.excludeSiteContent"
|
||||||
|
[where]="data?.where"
|
||||||
(select)="onSelect($event)">
|
(select)="onSelect($event)">
|
||||||
</adf-content-node-selector-panel>
|
</adf-content-node-selector-panel>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
@@ -48,13 +48,13 @@ export class NodeSharedDirective implements OnChanges {
|
|||||||
|
|
||||||
constructor(private dialog: MatDialog, private zone: NgZone) {}
|
constructor(private dialog: MatDialog, private zone: NgZone) {}
|
||||||
|
|
||||||
shareNode(node: NodeEntry) {
|
shareNode(nodeEntry: NodeEntry) {
|
||||||
if (node && node.entry && node.entry.isFile) {
|
if (nodeEntry && nodeEntry.entry && nodeEntry.entry.isFile) {
|
||||||
this.dialog.open(ShareDialogComponent, {
|
this.dialog.open(ShareDialogComponent, {
|
||||||
width: '600px',
|
width: '600px',
|
||||||
panelClass: 'adf-share-link-dialog',
|
panelClass: 'adf-share-link-dialog',
|
||||||
data: {
|
data: {
|
||||||
node: node,
|
node: nodeEntry,
|
||||||
baseShareUrl: this.baseShareUrl
|
baseShareUrl: this.baseShareUrl
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -63,7 +63,7 @@ export class NodeSharedDirective implements OnChanges {
|
|||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.zone.onStable.subscribe(() => {
|
this.zone.onStable.subscribe(() => {
|
||||||
if (this.node) {
|
if (this.node && this.node.entry) {
|
||||||
this.isFile = this.node.entry.isFile;
|
this.isFile = this.node.entry.isFile;
|
||||||
this.isShared = this.node.entry.properties['qshare:sharedId'];
|
this.isShared = this.node.entry.properties['qshare:sharedId'];
|
||||||
}
|
}
|
||||||
|
@@ -1269,6 +1269,24 @@ describe('DocumentList', () => {
|
|||||||
documentList.ngOnChanges({ currentFolderId: new SimpleChange(null, '-root-', false) });
|
documentList.ngOnChanges({ currentFolderId: new SimpleChange(null, '-root-', false) });
|
||||||
|
|
||||||
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
|
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
|
||||||
|
where: undefined,
|
||||||
|
maxItems: 25,
|
||||||
|
skipCount: 0,
|
||||||
|
rootFolderId: 'fake-id'
|
||||||
|
}, ['test-include']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add where in the server request when present', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
documentList.currentFolderId = 'fake-id';
|
||||||
|
documentList.includeFields = ['test-include'];
|
||||||
|
documentList.where = '(isFolder=true)';
|
||||||
|
spyOn(documentListService, 'getFolder').and.callThrough();
|
||||||
|
|
||||||
|
documentList.ngOnChanges({ currentFolderId: new SimpleChange(null, '-root-', false) });
|
||||||
|
|
||||||
|
expect(documentListService.getFolder).toHaveBeenCalledWith(null, {
|
||||||
|
where: '(isFolder=true)',
|
||||||
maxItems: 25,
|
maxItems: 25,
|
||||||
skipCount: 0,
|
skipCount: 0,
|
||||||
rootFolderId: 'fake-id'
|
rootFolderId: 'fake-id'
|
||||||
|
@@ -39,7 +39,8 @@ import {
|
|||||||
ThumbnailService,
|
ThumbnailService,
|
||||||
CustomLoadingContentTemplateDirective,
|
CustomLoadingContentTemplateDirective,
|
||||||
CustomNoPermissionTemplateDirective,
|
CustomNoPermissionTemplateDirective,
|
||||||
CustomEmptyContentTemplateDirective
|
CustomEmptyContentTemplateDirective,
|
||||||
|
RequestPaginationModel
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
|
|
||||||
import { Node, NodeEntry, NodePaging } from '@alfresco/js-api';
|
import { Node, NodeEntry, NodePaging } from '@alfresco/js-api';
|
||||||
@@ -88,6 +89,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
@Input()
|
@Input()
|
||||||
includeFields: string[];
|
includeFields: string[];
|
||||||
|
|
||||||
|
/** filter the Node list using the where condition of the rest api for example (isFolder=true) see the rest api documentation for more information. */
|
||||||
|
@Input()
|
||||||
|
where: string;
|
||||||
|
|
||||||
/** Change the display mode of the table. Can be "list" or "gallery". */
|
/** Change the display mode of the table. Can be "list" or "gallery". */
|
||||||
@Input()
|
@Input()
|
||||||
display: string = DisplayMode.List;
|
display: string = DisplayMode.List;
|
||||||
@@ -260,7 +265,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
// @deprecated 3.0.0
|
// @deprecated 3.0.0
|
||||||
folderNode: Node;
|
folderNode: Node;
|
||||||
|
|
||||||
private _pagination: BehaviorSubject<PaginationModel>;
|
private _pagination: PaginationModel;
|
||||||
|
private $pagination: BehaviorSubject<PaginationModel>;
|
||||||
|
|
||||||
private layoutPresets = {};
|
private layoutPresets = {};
|
||||||
private subscriptions: Subscription[] = [];
|
private subscriptions: Subscription[] = [];
|
||||||
private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
|
private rowMenuCache: { [key: string]: ContentActionModel[] } = {};
|
||||||
@@ -274,6 +281,13 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
private customResourcesService: CustomResourcesService,
|
private customResourcesService: CustomResourcesService,
|
||||||
private contentService: ContentService,
|
private contentService: ContentService,
|
||||||
private thumbnailService: ThumbnailService) {
|
private thumbnailService: ThumbnailService) {
|
||||||
|
|
||||||
|
this._pagination = <PaginationModel> {
|
||||||
|
maxItems: this.maxItems || this.preferences.paginationSize,
|
||||||
|
skipCount: 0,
|
||||||
|
totalItems: 0,
|
||||||
|
hasMoreItems: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getContextActions(node: NodeEntry) {
|
getContextActions(node: NodeEntry) {
|
||||||
@@ -310,17 +324,10 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
get pagination(): BehaviorSubject<PaginationModel> {
|
get pagination(): BehaviorSubject<PaginationModel> {
|
||||||
if (!this._pagination) {
|
if (!this.$pagination) {
|
||||||
let maxItems = this.maxItems || this.preferences.paginationSize;
|
this.$pagination = new BehaviorSubject<PaginationModel>(this._pagination);
|
||||||
let defaultPagination = <PaginationModel> {
|
|
||||||
maxItems: maxItems,
|
|
||||||
skipCount: 0,
|
|
||||||
totalItems: 0,
|
|
||||||
hasMoreItems: false
|
|
||||||
};
|
|
||||||
this._pagination = new BehaviorSubject<PaginationModel>(defaultPagination);
|
|
||||||
}
|
}
|
||||||
return this._pagination;
|
return this.$pagination;
|
||||||
}
|
}
|
||||||
|
|
||||||
isMobile(): boolean {
|
isMobile(): boolean {
|
||||||
@@ -412,7 +419,9 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
this.loadFolder();
|
this.loadFolder();
|
||||||
} else if (this.data) {
|
} else if (this.data) {
|
||||||
if (changes.node && changes.node.currentValue) {
|
if (changes.node && changes.node.currentValue) {
|
||||||
this.data.loadPage(changes.node.currentValue);
|
let merge = this._pagination ? this._pagination.merge : false;
|
||||||
|
|
||||||
|
this.data.loadPage(changes.node.currentValue, merge);
|
||||||
this.onDataReady(changes.node.currentValue);
|
this.onDataReady(changes.node.currentValue);
|
||||||
} else if (changes.imageResolver) {
|
} else if (changes.imageResolver) {
|
||||||
this.data.setImageResolver(changes.imageResolver.currentValue);
|
this.data.setImageResolver(changes.imageResolver.currentValue);
|
||||||
@@ -424,7 +433,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
this.ngZone.run(() => {
|
this.ngZone.run(() => {
|
||||||
this.resetSelection();
|
this.resetSelection();
|
||||||
if (this.node) {
|
if (this.node) {
|
||||||
this.data.loadPage(this.node, this.pagination.getValue().merge);
|
this.data.loadPage(this.node, this._pagination.merge);
|
||||||
this.onDataReady(this.node);
|
this.onDataReady(this.node);
|
||||||
} else {
|
} else {
|
||||||
this.loadFolder();
|
this.loadFolder();
|
||||||
@@ -579,7 +588,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadFolder() {
|
loadFolder() {
|
||||||
if (!this.pagination.getValue().merge) {
|
if (!this._pagination.merge) {
|
||||||
this.setLoadingState(true);
|
this.setLoadingState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,33 +602,36 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
loadFolderByNodeId(nodeId: string) {
|
loadFolderByNodeId(nodeId: string) {
|
||||||
if (this.customResourcesService.isCustomSource(nodeId)) {
|
if (this.customResourcesService.isCustomSource(nodeId)) {
|
||||||
this.updateCustomSourceData(nodeId);
|
this.updateCustomSourceData(nodeId);
|
||||||
this.customResourcesService.loadFolderByNodeId(nodeId, this.pagination.getValue(), this.includeFields)
|
this.customResourcesService.loadFolderByNodeId(nodeId, this._pagination, this.includeFields)
|
||||||
.subscribe((page: NodePaging) => {
|
.subscribe((nodePaging: NodePaging) => {
|
||||||
this.onPageLoaded(page);
|
this.onPageLoaded(nodePaging);
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
this.error.emit(err);
|
this.error.emit(err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let pagination = this.pagination.getValue();
|
|
||||||
this.documentListService.getFolder(null, {
|
this.documentListService.getFolder(null, {
|
||||||
maxItems: pagination.maxItems,
|
maxItems: this._pagination.maxItems,
|
||||||
skipCount: pagination.skipCount,
|
skipCount: this._pagination.skipCount,
|
||||||
rootFolderId: nodeId
|
rootFolderId: nodeId,
|
||||||
|
where: this.where
|
||||||
}, this.includeFields)
|
}, this.includeFields)
|
||||||
.subscribe((nodePaging: NodePaging) => {
|
.subscribe((nodePaging: NodePaging) => {
|
||||||
this.data.loadPage(nodePaging, this.pagination.getValue().merge);
|
this.onPageLoaded(nodePaging);
|
||||||
this.setLoadingState(false);
|
this.getSourceNodeWithPath(nodeId);
|
||||||
this.onDataReady(nodePaging);
|
|
||||||
this.documentListService.getFolderNode(nodeId, this.includeFields).subscribe((nodeEntry: NodeEntry) => {
|
|
||||||
this.folderNode = nodeEntry.entry;
|
|
||||||
this.$folderNode.next(this.folderNode);
|
|
||||||
});
|
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
this.handleError(err);
|
this.handleError(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSourceNodeWithPath(nodeId: string) {
|
||||||
|
this.documentListService.getFolderNode(nodeId, this.includeFields).subscribe((nodeEntry: NodeEntry) => {
|
||||||
|
this.folderNode = nodeEntry.entry;
|
||||||
|
this.$folderNode.next(this.folderNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
resetSelection() {
|
resetSelection() {
|
||||||
this.dataTable.resetSelection();
|
this.dataTable.resetSelection();
|
||||||
this.selection = [];
|
this.selection = [];
|
||||||
@@ -628,7 +640,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
|
|
||||||
onPageLoaded(nodePaging: NodePaging) {
|
onPageLoaded(nodePaging: NodePaging) {
|
||||||
if (nodePaging) {
|
if (nodePaging) {
|
||||||
this.data.loadPage(nodePaging, this.pagination.getValue().merge);
|
this.data.loadPage(nodePaging, this._pagination.merge);
|
||||||
this.setLoadingState(false);
|
this.setLoadingState(false);
|
||||||
this.onDataReady(nodePaging);
|
this.onDataReady(nodePaging);
|
||||||
}
|
}
|
||||||
@@ -787,12 +799,13 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
|
|||||||
|
|
||||||
private onDataReady(nodePaging: NodePaging) {
|
private onDataReady(nodePaging: NodePaging) {
|
||||||
this.ready.emit(nodePaging);
|
this.ready.emit(nodePaging);
|
||||||
|
|
||||||
this.pagination.next(nodePaging.list.pagination);
|
this.pagination.next(nodePaging.list.pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePagination(pagination: PaginationModel) {
|
updatePagination(requestPaginationModel: RequestPaginationModel) {
|
||||||
this.pagination.next(pagination);
|
this._pagination.maxItems = requestPaginationModel.maxItems;
|
||||||
|
this._pagination.merge = requestPaginationModel.merge;
|
||||||
|
this._pagination.skipCount = requestPaginationModel.skipCount;
|
||||||
this.reload();
|
this.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -245,11 +245,11 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadPage(page: NodePaging, merge: boolean = false) {
|
public loadPage(nodePaging: NodePaging, merge: boolean = false) {
|
||||||
let shareDataRows: ShareDataRow[] = [];
|
let shareDataRows: ShareDataRow[] = [];
|
||||||
|
|
||||||
if (page && page.list) {
|
if (nodePaging && nodePaging.list) {
|
||||||
let nodeEntries: NodeEntry[] = page.list.entries;
|
let nodeEntries: NodeEntry[] = nodePaging.list.entries;
|
||||||
if (nodeEntries && nodeEntries.length > 0) {
|
if (nodeEntries && nodeEntries.length > 0) {
|
||||||
shareDataRows = nodeEntries.map((item) => new ShareDataRow(item, this.contentService, this.permissionsStyle, this.thumbnailService));
|
shareDataRows = nodeEntries.map((item) => new ShareDataRow(item, this.contentService, this.permissionsStyle, this.thumbnailService));
|
||||||
|
|
||||||
|
@@ -105,6 +105,9 @@ export class DocumentListService {
|
|||||||
if (opts.skipCount) {
|
if (opts.skipCount) {
|
||||||
params.skipCount = opts.skipCount;
|
params.skipCount = opts.skipCount;
|
||||||
}
|
}
|
||||||
|
if (opts.where) {
|
||||||
|
params.where = opts.where;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return from(this.apiService.getInstance().nodes.getNodeChildren(rootNodeId, params)).pipe(
|
return from(this.apiService.getInstance().nodes.getNodeChildren(rootNodeId, params)).pipe(
|
||||||
|
@@ -20,15 +20,15 @@ import { Pagination } from '@alfresco/js-api';
|
|||||||
export class PaginationModel extends Pagination {
|
export class PaginationModel extends Pagination {
|
||||||
merge?: boolean;
|
merge?: boolean;
|
||||||
|
|
||||||
constructor(obj?: any) {
|
constructor(input?: any) {
|
||||||
super(obj);
|
super(input);
|
||||||
if (obj) {
|
if (input) {
|
||||||
this.count = obj.count;
|
this.count = input.count;
|
||||||
this.hasMoreItems = obj.hasMoreItems ? obj.hasMoreItems : false;
|
this.hasMoreItems = input.hasMoreItems ? input.hasMoreItems : false;
|
||||||
this.merge = obj.merge ? obj.merge : false;
|
this.merge = input.merge ? input.merge : false;
|
||||||
this.totalItems = obj.totalItems;
|
this.totalItems = input.totalItems;
|
||||||
this.skipCount = obj.skipCount;
|
this.skipCount = input.skipCount;
|
||||||
this.maxItems = obj.maxItems;
|
this.maxItems = input.maxItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,3 +24,4 @@ export * from './ecm-company.model';
|
|||||||
export * from './redirection.model';
|
export * from './redirection.model';
|
||||||
export * from './pagination.model';
|
export * from './pagination.model';
|
||||||
export * from './oauth-config.model';
|
export * from './oauth-config.model';
|
||||||
|
export * from './request-pagination.model';
|
||||||
|
31
lib/core/models/request-pagination.model.ts
Normal file
31
lib/core/models/request-pagination.model.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2016 Alfresco Software, Ltd.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class RequestPaginationModel {
|
||||||
|
|
||||||
|
skipCount?: number;
|
||||||
|
|
||||||
|
maxItems?: number;
|
||||||
|
|
||||||
|
merge?: boolean = false;
|
||||||
|
|
||||||
|
constructor(input?: any) {
|
||||||
|
if (input) {
|
||||||
|
Object.assign(this, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -111,6 +111,36 @@ describe('InfinitePaginationComponent', () => {
|
|||||||
expect(loadMoreButton).not.toBeNull();
|
expect(loadMoreButton).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should NOT show the load more button if there are no more elements to load', (done) => {
|
||||||
|
pagination = { maxItems: 444, skipCount: 25, totalItems: 30, hasMoreItems: false };
|
||||||
|
|
||||||
|
component.target.pagination.next(pagination);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
component.onLoadMore();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let loadMoreButton = fixture.debugElement.query(By.css('[data-automation-id="adf-infinite-pagination-button"]'));
|
||||||
|
expect(loadMoreButton).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the load more button if there are more elements to load', (done) => {
|
||||||
|
pagination = { maxItems: 444, skipCount: 25, totalItems: 55, hasMoreItems: true };
|
||||||
|
|
||||||
|
component.target.pagination.next(pagination);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
let loadMoreButton = fixture.debugElement.query(By.css('[data-automation-id="adf-infinite-pagination-button"]'));
|
||||||
|
expect(loadMoreButton).not.toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should NOT show anything if pagination has NO more items', () => {
|
it('should NOT show anything if pagination has NO more items', () => {
|
||||||
pagination.hasMoreItems = false;
|
pagination.hasMoreItems = false;
|
||||||
component.target.updatePagination(pagination);
|
component.target.updatePagination(pagination);
|
||||||
@@ -123,15 +153,16 @@ describe('InfinitePaginationComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should trigger the loadMore event with the proper pagination object', (done) => {
|
it('should trigger the loadMore event with the proper pagination object', (done) => {
|
||||||
pagination.hasMoreItems = true;
|
pagination = { maxItems: 444, skipCount: 25, totalItems: 55, hasMoreItems: true };
|
||||||
pagination.skipCount = 5;
|
|
||||||
component.target.updatePagination(pagination);
|
component.target.pagination.next(pagination);
|
||||||
|
|
||||||
component.isLoading = false;
|
component.isLoading = false;
|
||||||
component.pageSize = 5;
|
component.pageSize = 5;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
component.loadMore.subscribe((newPagination: Pagination) => {
|
component.loadMore.subscribe((newPagination: Pagination) => {
|
||||||
expect(newPagination.skipCount).toBe(10);
|
expect(newPagination.skipCount).toBe(5);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -166,10 +197,9 @@ describe('InfinitePaginationComponent', () => {
|
|||||||
component.onLoadMore();
|
component.onLoadMore();
|
||||||
|
|
||||||
expect(spyTarget).toHaveBeenCalledWith({
|
expect(spyTarget).toHaveBeenCalledWith({
|
||||||
maxItems: 444,
|
|
||||||
skipCount: 25,
|
skipCount: 25,
|
||||||
totalItems: 888,
|
maxItems: 25,
|
||||||
hasMoreItems: true,
|
hasMoreItems: false,
|
||||||
merge: true
|
merge: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -182,10 +212,9 @@ describe('InfinitePaginationComponent', () => {
|
|||||||
component.onLoadMore();
|
component.onLoadMore();
|
||||||
|
|
||||||
expect(spyTarget).toHaveBeenCalledWith({
|
expect(spyTarget).toHaveBeenCalledWith({
|
||||||
maxItems: 444,
|
maxItems: 7,
|
||||||
skipCount: 7,
|
skipCount: 7,
|
||||||
totalItems: 888,
|
hasMoreItems: false,
|
||||||
hasMoreItems: true,
|
|
||||||
merge: true
|
merge: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -27,6 +27,7 @@ import { PaginatedComponent } from './paginated-component.interface';
|
|||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { PaginationComponentInterface } from './pagination-component.interface';
|
import { PaginationComponentInterface } from './pagination-component.interface';
|
||||||
import { PaginationModel } from '../models/pagination.model';
|
import { PaginationModel } from '../models/pagination.model';
|
||||||
|
import { RequestPaginationModel } from '../models/request-pagination.model';
|
||||||
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
|
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -39,12 +40,6 @@ import { UserPreferencesService, UserPreferenceValues } from '../services/user-p
|
|||||||
})
|
})
|
||||||
export class InfinitePaginationComponent implements OnInit, OnDestroy, PaginationComponentInterface {
|
export class InfinitePaginationComponent implements OnInit, OnDestroy, PaginationComponentInterface {
|
||||||
|
|
||||||
static DEFAULT_PAGINATION: PaginationModel = {
|
|
||||||
skipCount: 0,
|
|
||||||
hasMoreItems: false,
|
|
||||||
merge: true
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Component that provides custom pagination support. */
|
/** Component that provides custom pagination support. */
|
||||||
@Input()
|
@Input()
|
||||||
target: PaginatedComponent;
|
target: PaginatedComponent;
|
||||||
@@ -59,10 +54,15 @@ export class InfinitePaginationComponent implements OnInit, OnDestroy, Paginatio
|
|||||||
|
|
||||||
/** Emitted when the "Load More" button is clicked. */
|
/** Emitted when the "Load More" button is clicked. */
|
||||||
@Output()
|
@Output()
|
||||||
loadMore: EventEmitter<PaginationModel> = new EventEmitter<PaginationModel>();
|
loadMore: EventEmitter<RequestPaginationModel> = new EventEmitter<RequestPaginationModel>();
|
||||||
|
|
||||||
pagination: PaginationModel;
|
pagination: PaginationModel;
|
||||||
|
|
||||||
|
requestPaginationModel: RequestPaginationModel = {
|
||||||
|
skipCount: 0,
|
||||||
|
merge: true
|
||||||
|
};
|
||||||
|
|
||||||
private paginationSubscription: Subscription;
|
private paginationSubscription: Subscription;
|
||||||
|
|
||||||
constructor(private cdr: ChangeDetectorRef, private userPreferencesService: UserPreferencesService) {
|
constructor(private cdr: ChangeDetectorRef, private userPreferencesService: UserPreferencesService) {
|
||||||
@@ -73,6 +73,11 @@ export class InfinitePaginationComponent implements OnInit, OnDestroy, Paginatio
|
|||||||
this.paginationSubscription = this.target.pagination.subscribe((pagination) => {
|
this.paginationSubscription = this.target.pagination.subscribe((pagination) => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.pagination = pagination;
|
this.pagination = pagination;
|
||||||
|
|
||||||
|
if (!this.pagination.hasMoreItems) {
|
||||||
|
this.pagination.hasMoreItems = false;
|
||||||
|
}
|
||||||
|
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -80,26 +85,18 @@ export class InfinitePaginationComponent implements OnInit, OnDestroy, Paginatio
|
|||||||
this.userPreferencesService.select(UserPreferenceValues.PaginationSize).subscribe((pagSize) => {
|
this.userPreferencesService.select(UserPreferenceValues.PaginationSize).subscribe((pagSize) => {
|
||||||
this.pageSize = this.pageSize || pagSize;
|
this.pageSize = this.pageSize || pagSize;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.pagination) {
|
|
||||||
this.pagination = InfinitePaginationComponent.DEFAULT_PAGINATION;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoadMore() {
|
onLoadMore() {
|
||||||
this.pagination.skipCount += this.pageSize;
|
this.requestPaginationModel.skipCount += this.pageSize;
|
||||||
this.pagination.merge = true;
|
this.requestPaginationModel.merge = true;
|
||||||
this.loadMore.next(this.pagination);
|
this.requestPaginationModel.maxItems = this.pageSize;
|
||||||
|
|
||||||
if (this.pagination.skipCount >= this.pagination.totalItems || !this.pagination.hasMoreItems) {
|
this.loadMore.next(this.requestPaginationModel);
|
||||||
this.pagination.hasMoreItems = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.target) {
|
if (this.target) {
|
||||||
this.target.pagination.value.merge = this.pagination.merge;
|
|
||||||
this.target.pagination.value.skipCount = this.pagination.skipCount;
|
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.target.updatePagination(<PaginationModel> this.pagination);
|
this.target.updatePagination(<RequestPaginationModel> this.requestPaginationModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,8 +17,9 @@
|
|||||||
|
|
||||||
import { PaginationModel } from '../models/pagination.model';
|
import { PaginationModel } from '../models/pagination.model';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
import { RequestPaginationModel } from '../models/request-pagination.model';
|
||||||
|
|
||||||
export interface PaginatedComponent {
|
export interface PaginatedComponent {
|
||||||
pagination: BehaviorSubject<PaginationModel>;
|
pagination: BehaviorSubject<PaginationModel>;
|
||||||
updatePagination(pagination: PaginationModel);
|
updatePagination(requestPaginationModel: RequestPaginationModel);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user