[Paging] Added for Organization Users, Pages, and Collections (#539)

* Updating jslib

* Added paging for Organizational Users, Groups, and Collections

* Updated jslib fb7335b -> 2858724
This commit is contained in:
Vincent Salucci 2020-05-22 11:26:43 -05:00 committed by GitHub
parent 179884cf93
commit 7301158e54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 138 additions and 9 deletions

View File

@ -16,9 +16,11 @@
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span class="sr-only">{{'loading' | i18n}}</span>
</ng-container>
<ng-container *ngIf="!loading && (collections | search:searchText:'name':'id') as searchedCollections">
<ng-container
*ngIf="!loading && (isPaging() ? pagedCollections : collections | search:searchText:'name':'id') as searchedCollections">
<p *ngIf="!searchedCollections.length">{{'noCollectionsInList' | i18n}}</p>
<table class="table table-hover table-list" *ngIf="searchedCollections.length">
<table class="table table-hover table-list" *ngIf="searchedCollections.length" infiniteScroll
[infiniteScrollDistance]="1" [infiniteScrollDisabled]="!isPaging()" (scrolled)="loadMore()">
<tbody>
<tr *ngFor="let c of searchedCollections">
<td>

View File

@ -14,6 +14,7 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SearchService } from 'jslib/abstractions/search.service';
import { UserService } from 'jslib/abstractions/user.service';
import { CollectionData } from 'jslib/models/data/collectionData';
@ -40,15 +41,20 @@ export class CollectionsComponent implements OnInit {
loading = true;
organizationId: string;
collections: CollectionView[];
pagedCollections: CollectionView[];
searchText: string;
protected didScroll = false;
protected pageSize = 100;
private pagedCollectionsCount = 0;
private modal: ModalComponent = null;
constructor(private apiService: ApiService, private route: ActivatedRoute,
private collectionService: CollectionService, private componentFactoryResolver: ComponentFactoryResolver,
private analytics: Angulartics2, private toasterService: ToasterService,
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
private userService: UserService) { }
private userService: UserService, private searchService: SearchService) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
@ -74,9 +80,27 @@ export class CollectionsComponent implements OnInit {
const collections = response.data.filter((c) => c.organizationId === this.organizationId).map((r) =>
new Collection(new CollectionData(r as CollectionDetailsResponse)));
this.collections = await this.collectionService.decryptMany(collections);
this.resetPaging();
this.loading = false;
}
loadMore() {
if (this.collections.length <= this.pageSize) {
return;
}
const pagedLength = this.pagedCollections.length;
let pagedSize = this.pageSize;
if (pagedLength === 0 && this.pagedCollectionsCount > this.pageSize) {
pagedSize = this.pagedCollectionsCount;
}
if (this.collections.length > pagedLength) {
this.pagedCollections =
this.pagedCollections.concat(this.collections.slice(pagedLength, pagedLength + pagedSize));
}
this.pagedCollectionsCount = this.pagedCollections.length;
this.didScroll = this.pagedCollections.length > this.pageSize;
}
edit(collection: CollectionView) {
if (this.modal != null) {
this.modal.close();
@ -147,10 +171,28 @@ export class CollectionsComponent implements OnInit {
});
}
async resetPaging() {
this.pagedCollections = [];
this.loadMore();
}
isSearching() {
return this.searchService.isSearchable(this.searchText);
}
isPaging() {
const searching = this.isSearching();
if (searching && this.didScroll) {
this.resetPaging();
}
return !searching && this.collections.length > this.pageSize;
}
private removeCollection(collection: CollectionView) {
const index = this.collections.indexOf(collection);
if (index > -1) {
this.collections.splice(index, 1);
this.resetPaging();
}
}
}

View File

@ -16,9 +16,10 @@
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span class="sr-only">{{'loading' | i18n}}</span>
</ng-container>
<ng-container *ngIf="!loading && (groups | search:searchText:'name':'id') as searchedGroups">
<ng-container *ngIf="!loading && (isPaging() ? pagedGroups : groups | search:searchText:'name':'id') as searchedGroups">
<p *ngIf="!searchedGroups.length">{{'noGroupsInList' | i18n}}</p>
<table class="table table-hover table-list" *ngIf="searchedGroups.length">
<table class="table table-hover table-list" *ngIf="searchedGroups.length" infiniteScroll
[infiniteScrollDistance]="1" [infiniteScrollDisabled]="!isPaging()" (scrolled)="loadMore()">
<tbody>
<tr *ngFor="let g of searchedGroups">
<td>

View File

@ -16,6 +16,7 @@ import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SearchService } from 'jslib/abstractions/search.service';
import { UserService } from 'jslib/abstractions/user.service';
import { GroupResponse } from 'jslib/models/response/groupResponse';
@ -37,15 +38,20 @@ export class GroupsComponent implements OnInit {
loading = true;
organizationId: string;
groups: GroupResponse[];
pagedGroups: GroupResponse[];
searchText: string;
protected didScroll = false;
protected pageSize = 100;
private pagedGroupsCount = 0;
private modal: ModalComponent = null;
constructor(private apiService: ApiService, private route: ActivatedRoute,
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
private analytics: Angulartics2, private toasterService: ToasterService,
private platformUtilsService: PlatformUtilsService, private userService: UserService,
private router: Router) { }
private router: Router, private searchService: SearchService) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
@ -70,9 +76,26 @@ export class GroupsComponent implements OnInit {
const groups = response.data != null && response.data.length > 0 ? response.data : [];
groups.sort(Utils.getSortFunction(this.i18nService, 'name'));
this.groups = groups;
this.resetPaging();
this.loading = false;
}
loadMore() {
if (this.groups.length <= this.pageSize) {
return;
}
const pagedLength = this.pagedGroups.length;
let pagedSize = this.pageSize;
if (pagedLength === 0 && this.pagedGroupsCount > this.pageSize) {
pagedSize = this.pagedGroupsCount;
}
if (this.groups.length > pagedLength) {
this.pagedGroups = this.pagedGroups.concat(this.groups.slice(pagedLength, pagedLength + pagedSize));
}
this.pagedGroupsCount = this.pagedGroups.length;
this.didScroll = this.pagedGroups.length > this.pageSize;
}
edit(group: GroupResponse) {
if (this.modal != null) {
this.modal.close();
@ -142,10 +165,28 @@ export class GroupsComponent implements OnInit {
});
}
async resetPaging() {
this.pagedGroups = [];
this.loadMore();
}
isSearching() {
return this.searchService.isSearchable(this.searchText);
}
isPaging() {
const searching = this.isSearching();
if (searching && this.didScroll) {
this.resetPaging();
}
return !searching && this.groups.length > this.pageSize;
}
private removeGroup(group: GroupResponse) {
const index = this.groups.indexOf(group);
if (index > -1) {
this.groups.splice(index, 1);
this.resetPaging();
}
}
}

View File

@ -35,13 +35,15 @@
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
<span class="sr-only">{{'loading' | i18n}}</span>
</ng-container>
<ng-container *ngIf="!loading && (users | search:searchText:'name':'email':'id') as searchedUsers">
<ng-container
*ngIf="!loading && (isPaging() ? pagedUsers : users | search:searchText:'name':'email':'id') as searchedUsers">
<p *ngIf="!searchedUsers.length">{{'noUsersInList' | i18n}}</p>
<ng-container *ngIf="searchedUsers.length">
<app-callout type="info" title="{{'confirmUsers' | i18n}}" icon="fa-check-circle" *ngIf="showConfirmUsers">
{{'usersNeedConfirmed' | i18n}}
</app-callout>
<table class="table table-hover table-list">
<table class="table table-hover table-list" infiniteScroll [infiniteScrollDistance]="1"
[infiniteScrollDisabled]="!isPaging()" (scrolled)="loadMore()">
<tbody>
<tr *ngFor="let u of searchedUsers">
<td width="30">

View File

@ -19,6 +19,7 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SearchService } from 'jslib/abstractions/search.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service';
@ -50,6 +51,7 @@ export class PeopleComponent implements OnInit {
loading = true;
organizationId: string;
users: OrganizationUserUserDetailsResponse[];
pagedUsers: OrganizationUserUserDetailsResponse[];
searchText: string;
status: OrganizationUserStatusType = null;
statusMap = new Map<OrganizationUserStatusType, OrganizationUserUserDetailsResponse[]>();
@ -59,6 +61,10 @@ export class PeopleComponent implements OnInit {
accessEvents = false;
accessGroups = false;
protected didScroll = false;
protected pageSize = 100;
private pagedUsersCount = 0;
private modal: ModalComponent = null;
private allUsers: OrganizationUserUserDetailsResponse[];
@ -67,7 +73,7 @@ export class PeopleComponent implements OnInit {
private platformUtilsService: PlatformUtilsService, private analytics: Angulartics2,
private toasterService: ToasterService, private cryptoService: CryptoService,
private userService: UserService, private router: Router,
private storageService: StorageService) { }
private storageService: StorageService, private searchService: SearchService) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
@ -119,6 +125,23 @@ export class PeopleComponent implements OnInit {
} else {
this.users = this.allUsers;
}
this.resetPaging();
}
loadMore() {
if (this.users.length <= this.pageSize) {
return;
}
const pagedLength = this.pagedUsers.length;
let pagedSize = this.pageSize;
if (pagedLength === 0 && this.pagedUsersCount > this.pageSize) {
pagedSize = this.pagedUsersCount;
}
if (this.users.length > pagedLength) {
this.pagedUsers = this.pagedUsers.concat(this.users.slice(pagedLength, pagedLength + pagedSize));
}
this.pagedUsersCount = this.pagedUsers.length;
this.didScroll = this.pagedUsers.length > this.pageSize;
}
get allCount() {
@ -294,6 +317,23 @@ export class PeopleComponent implements OnInit {
});
}
async resetPaging() {
this.pagedUsers = [];
this.loadMore();
}
isSearching() {
return this.searchService.isSearchable(this.searchText);
}
isPaging() {
const searching = this.isSearching();
if (searching && this.didScroll) {
this.resetPaging();
}
return !searching && this.users.length > this.pageSize;
}
private async doConfirmation(user: OrganizationUserUserDetailsResponse) {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
@ -313,6 +353,7 @@ export class PeopleComponent implements OnInit {
let index = this.users.indexOf(user);
if (index > -1) {
this.users.splice(index, 1);
this.resetPaging();
}
if (this.statusMap.has(OrganizationUserStatusType.Accepted)) {
index = this.statusMap.get(OrganizationUserStatusType.Accepted).indexOf(user);