From 87982df0fd91cbed5c2bcee9ff3f1f791643b531 Mon Sep 17 00:00:00 2001 From: Bruno Reis Date: Thu, 19 May 2022 02:57:19 -0300 Subject: [PATCH] Added members count and load icon (#1061) --- .../assets/js/app/browse/UserItemsTreeGrid.ts | 18 ++++++++++++++++-- .../filter/PrincipalBrowseFilterPanel.ts | 10 +++++++--- .../app/event/UserFilteredDataScrollEvent.ts | 8 +++++++- .../js/app/event/UserItemsStopScrollEvent.ts | 19 +++++++++++++++++++ .../assets/js/app/view/MembersListing.ts | 8 ++++++++ .../js/app/view/UserItemStatisticsPanel.ts | 5 +++-- 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/assets/js/app/event/UserItemsStopScrollEvent.ts diff --git a/src/main/resources/assets/js/app/browse/UserItemsTreeGrid.ts b/src/main/resources/assets/js/app/browse/UserItemsTreeGrid.ts index a9dfa0024..6ed49f0df 100644 --- a/src/main/resources/assets/js/app/browse/UserItemsTreeGrid.ts +++ b/src/main/resources/assets/js/app/browse/UserItemsTreeGrid.ts @@ -26,7 +26,9 @@ import {ListPrincipalsKeysResult, ListPrincipalsNamesRequest} from '../../graphq import {DefaultErrorHandler} from 'lib-admin-ui/DefaultErrorHandler'; import {GetPrincipalsExistenceRequest} from '../../graphql/principal/GetPrincipalsExistenceRequest'; import {UserFilteredDataScrollEvent} from '../event/UserFilteredDataScrollEvent'; +import {UserItemsStopScrollEvent} from '../event/UserItemsStopScrollEvent'; import {AppHelper} from 'lib-admin-ui/util/AppHelper'; +import {LoadMask} from 'lib-admin-ui/ui/mask/LoadMask'; export class UserItemsTreeGrid extends TreeGrid { @@ -34,6 +36,7 @@ export class UserItemsTreeGrid private treeGridActions: UserTreeGridActions; private searchString: string; private searchTypes: UserItemType[]; + private loadMask: LoadMask; constructor() { @@ -70,6 +73,8 @@ export class UserItemsTreeGrid this.setContextMenu(new TreeGridContextMenu(this.treeGridActions)); + this.loadMask = new LoadMask(this); + this.initEventHandlers(); } @@ -84,8 +89,11 @@ export class UserItemsTreeGrid const numberOfItemsToAdd = 30; const nextNumberOfItems = currentNumberOfItems + numberOfItemsToAdd; - if(this.getGrid().getViewport().bottom === currentNumberOfItems){ - new UserFilteredDataScrollEvent(nextNumberOfItems).fire(); + if (this.getGrid().getViewport().bottom === currentNumberOfItems) { + this.loadMask.show(); + new UserFilteredDataScrollEvent(currentNumberOfItems, nextNumberOfItems).fire(); + } else { + this.loadMask.hide(); } }, 100); @@ -108,6 +116,12 @@ export class UserItemsTreeGrid this.getGrid().unsubscribeOnScroll(triggerFilteredDataScrollEvent); }); + UserItemsStopScrollEvent.on(() => { + this.loadMask.hide(); + + this.getGrid().unsubscribeOnScroll(triggerFilteredDataScrollEvent); + }); + this.getGrid().subscribeOnDblClick((event, data) => { if (this.isActive()) { diff --git a/src/main/resources/assets/js/app/browse/filter/PrincipalBrowseFilterPanel.ts b/src/main/resources/assets/js/app/browse/filter/PrincipalBrowseFilterPanel.ts index beefd6ad0..23155982d 100644 --- a/src/main/resources/assets/js/app/browse/filter/PrincipalBrowseFilterPanel.ts +++ b/src/main/resources/assets/js/app/browse/filter/PrincipalBrowseFilterPanel.ts @@ -18,6 +18,7 @@ import {UserItem} from 'lib-admin-ui/security/UserItem'; import {SearchInputValues} from 'lib-admin-ui/query/SearchInputValues'; import {Exception} from 'lib-admin-ui/Exception'; import {UserFilteredDataScrollEvent} from '../../event/UserFilteredDataScrollEvent'; +import {UserItemsStopScrollEvent} from '../../event/UserItemsStopScrollEvent'; export class PrincipalBrowseFilterPanel extends BrowseFilterPanel { @@ -36,8 +37,7 @@ export class PrincipalBrowseFilterPanel private initEventHandlers() { UserFilteredDataScrollEvent.on((event) => { - const newCounterAfterScroll = event.getCount(); - this.searchDataAndHandleResponse(newCounterAfterScroll); + this.searchDataAndHandleResponse(event.getPrevCount(), event.getCount()); }); } @@ -100,7 +100,7 @@ export class PrincipalBrowseFilterPanel } // setCount(100): Initially get only 100 users. The UserFilteredDataScrollEvent will request more if necessary. - private searchDataAndHandleResponse(count: number = 100): Q.Promise { + private searchDataAndHandleResponse(prevCount:number = 0, count: number = 100): Q.Promise { const types: UserItemType[] = this.getCheckedTypes(); const searchString: string = this.getSearchInputValues().getTextSearchFieldValue(); const itemIds: string[] = this.getSelectedItemIds(); @@ -112,6 +112,10 @@ export class PrincipalBrowseFilterPanel .setItems(itemIds) .sendAndParse() .then((result: ListUserItemsRequestResult) => { + if(result.total === prevCount) { + new UserItemsStopScrollEvent().fire(); + return; + } this.handleDataSearchResult(result, types, searchString); }).catch((reason: any) => { DefaultErrorHandler.handle(reason); diff --git a/src/main/resources/assets/js/app/event/UserFilteredDataScrollEvent.ts b/src/main/resources/assets/js/app/event/UserFilteredDataScrollEvent.ts index e151f1124..4cb014636 100644 --- a/src/main/resources/assets/js/app/event/UserFilteredDataScrollEvent.ts +++ b/src/main/resources/assets/js/app/event/UserFilteredDataScrollEvent.ts @@ -4,13 +4,19 @@ import {Event} from 'lib-admin-ui/event/Event'; export class UserFilteredDataScrollEvent extends Event { + private prevCount: number; private count: number; - constructor(count: number) { + constructor(prevCount:number, count: number) { super(); + this.prevCount = prevCount; this.count = count; } + public getPrevCount(): number { + return this.prevCount; + } + public getCount(): number { return this.count; } diff --git a/src/main/resources/assets/js/app/event/UserItemsStopScrollEvent.ts b/src/main/resources/assets/js/app/event/UserItemsStopScrollEvent.ts new file mode 100644 index 000000000..5b790d06f --- /dev/null +++ b/src/main/resources/assets/js/app/event/UserItemsStopScrollEvent.ts @@ -0,0 +1,19 @@ +import {ClassHelper} from 'lib-admin-ui/ClassHelper'; +import {Event} from 'lib-admin-ui/event/Event'; + +export class UserItemsStopScrollEvent + extends Event { + + + constructor() { + super(); + } + + static on(handler: (event: UserItemsStopScrollEvent) => void): void { + Event.bind(ClassHelper.getFullName(this), handler); + } + + static un(handler?: (event: UserItemsStopScrollEvent) => void): void { + Event.unbind(ClassHelper.getFullName(this), handler); + } +} diff --git a/src/main/resources/assets/js/app/view/MembersListing.ts b/src/main/resources/assets/js/app/view/MembersListing.ts index eaf531a4d..cefb32379 100644 --- a/src/main/resources/assets/js/app/view/MembersListing.ts +++ b/src/main/resources/assets/js/app/view/MembersListing.ts @@ -9,6 +9,7 @@ import {Principal} from 'lib-admin-ui/security/Principal'; import {PrincipalViewer} from 'lib-admin-ui/ui/security/PrincipalViewer'; import {AppHelper} from 'lib-admin-ui/util/AppHelper'; import {GetPrincipalsByKeysRequest} from '../../graphql/principal/GetPrincipalsByKeysRequest'; +import {LoadMask} from 'lib-admin-ui/ui/mask/LoadMask'; export class MembersListing extends DivEl { @@ -32,13 +33,20 @@ export class MembersListing extends DivEl { setParent(parent: Element): void { this.parent = parent; + this.addScrollToParent(); + } + private addScrollToParent(){ let chunkIndex = 1; + const scrollHandler = AppHelper.debounce(async (event:Event) => { const element = event.target as HTMLElement; const isScrollNearBottom = element.scrollTop >= 0.95 * (element.scrollHeight - element.clientHeight); if (isScrollNearBottom && chunkIndex < this.membersKeysChunks.length) { + const mask = new LoadMask(this.ulList.getLastChild()); + mask.show(); await this.populateList(chunkIndex); + mask.hide(); chunkIndex += 1; } }, 100); diff --git a/src/main/resources/assets/js/app/view/UserItemStatisticsPanel.ts b/src/main/resources/assets/js/app/view/UserItemStatisticsPanel.ts index 71808406d..952aa3857 100644 --- a/src/main/resources/assets/js/app/view/UserItemStatisticsPanel.ts +++ b/src/main/resources/assets/js/app/view/UserItemStatisticsPanel.ts @@ -188,9 +188,10 @@ export class UserItemStatisticsPanel } private createMembersGroup(groupOrRole: Group | Role): MembersListing { - const membersListing = new MembersListing(i18n('field.members'), 'members item-data-group'); + const memberKeys = groupOrRole.getMembers(); + const membersListing = new MembersListing(i18n('field.members') + ` (${memberKeys.length})`, 'members item-data-group'); membersListing.setParent(this); - membersListing.setMembersKeys(groupOrRole.getMembers()); + membersListing.setMembersKeys(memberKeys); membersListing.populateList(); return membersListing; }