Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect empty page message on local tables #2678

Merged
merged 3 commits into from
Jul 19, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 61 additions & 44 deletions src/frontend/app/shared/monitors/pagination-monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ import {
tap,
} from 'rxjs/operators';

import { getAPIRequestDataState, selectEntities } from '../../store/selectors/api.selectors';
import {
getAPIRequestDataState,
selectEntities,
} from '../../store/selectors/api.selectors';
import { selectPaginationState } from '../../store/selectors/pagination.selectors';
import { AppState } from './../../store/app-state';
import { ActionState } from './../../store/reducers/api-request-reducer/types';
import { PaginationEntityState } from './../../store/types/pagination.types';

export class PaginationMonitor<T = any> {
/**
* Emits the current page of entities.
*/
* Emits the current page of entities.
*/
public currentPage$: Observable<T[]>;
/**
* Emits a boolean stating if the current page is fetching or not.
*/
* Emits a boolean stating if the current page is fetching or not.
*/
public fetchingCurrentPage$: Observable<boolean>;
/**
* Emits a boolean stating if the current page has errored or not.
*/
* Emits a boolean stating if the current page has errored or not.
*/
public currentPageError$: Observable<boolean>;
/**
* All the information about the current pagination selection.
Expand All @@ -41,13 +44,9 @@ export class PaginationMonitor<T = any> {
constructor(
private store: Store<AppState>,
public paginationKey: string,
public schema: schema.Entity
public schema: schema.Entity,
) {
this.init(
store,
paginationKey,
schema
);
this.init(store, paginationKey, schema);
}

/**
Expand All @@ -60,9 +59,10 @@ export class PaginationMonitor<T = any> {
}
const currentPage = pagination.ids[pagination.currentPage];
const hasPageIds = !!currentPage;
const requestInfo = pagination.pageRequests[pagination.clientPagination.currentPage];
const requestInfo =
pagination.pageRequests[pagination.clientPagination.currentPage];
const hasPageRequestInfo = !!requestInfo;
const hasPage = hasPageIds && hasPageRequestInfo && !requestInfo.busy;
const hasPage = hasPageIds && (!hasPageRequestInfo || !requestInfo.busy);
return hasPage;
}

Expand All @@ -78,12 +78,18 @@ export class PaginationMonitor<T = any> {
* Gets the request info for the current page.
* @param pagination
*/
private getCurrentPageRequestInfo(pagination: PaginationEntityState): ActionState {
if (!pagination || !pagination.pageRequests || !pagination.pageRequests[pagination.currentPage]) {
private getCurrentPageRequestInfo(
pagination: PaginationEntityState,
): ActionState {
if (
!pagination ||
!pagination.pageRequests ||
!pagination.pageRequests[pagination.currentPage]
) {
return {
busy: false,
error: false,
message: ''
message: '',
};
} else {
return pagination.pageRequests[pagination.currentPage];
Expand All @@ -94,51 +100,49 @@ export class PaginationMonitor<T = any> {
private init(
store: Store<AppState>,
paginationKey: string,
schema: schema.Entity
schema: schema.Entity,
) {
this.pagination$ = this.createPaginationObservable(
store,
schema.key,
paginationKey
);
this.currentPage$ = this.createPageObservable(
this.pagination$,
schema
paginationKey,
);
this.currentPage$ = this.createPageObservable(this.pagination$, schema);
this.currentPageError$ = this.createErrorObservable(this.pagination$);
this.fetchingCurrentPage$ = this.createFetchingObservable(this.pagination$);
}

private createPaginationObservable(
store: Store<AppState>,
entityKey: string,
paginationKey: string
paginationKey: string,
) {
return store.select(selectPaginationState(entityKey, paginationKey))
.pipe(
distinctUntilChanged(),
filter(pag => !!pag)
);
return store.select(selectPaginationState(entityKey, paginationKey)).pipe(
distinctUntilChanged(),
filter(pag => !!pag),
);
}



private createPageObservable(
pagination$: Observable<PaginationEntityState>,
schema: schema.Entity
schema: schema.Entity,
) {
const entityObservable$ = this.store.select(selectEntities<T>(this.schema.key)).pipe(distinctUntilChanged());
const entityObservable$ = this.store
.select(selectEntities<T>(this.schema.key))
.pipe(distinctUntilChanged());
const allEntitiesObservable$ = this.store.select(getAPIRequestDataState);
return pagination$.pipe(
// Improve efficiency
observeOn(asapScheduler),
filter((pagination) => this.hasPage(pagination)),
filter(pagination => this.hasPage(pagination)),
distinctUntilChanged(this.isPageSameIsh),
combineLatestOperator(entityObservable$),
withLatestFrom(allEntitiesObservable$),
map(([[pagination], allEntities]) => {
const page = pagination.ids[pagination.currentPage] || [];
return page.length ? denormalize(page, [schema], allEntities).filter(ent => !!ent) : [];
return page.length
? denormalize(page, [schema], allEntities).filter(ent => !!ent)
: [];
}),
tag('de-norming ' + schema.key),
publishReplay(1),
Expand All @@ -149,30 +153,43 @@ export class PaginationMonitor<T = any> {
private isPageSameIsh(x: PaginationEntityState, y: PaginationEntityState) {
const samePage = x.currentPage === y.currentPage;
// It's possible that we need to compare the whole page request object but busy will do for now.
const samePageBusyState = samePage && x.pageRequests[x.currentPage].busy === y.pageRequests[y.currentPage].busy;
const samePageIdList = samePage && x.ids[x.currentPage] === y.ids[y.currentPage];
const samePageBusyState =
samePage &&
(
x.pageRequests[x.currentPage]
&&
x.pageRequests[x.currentPage].busy
) === (
y.pageRequests[y.currentPage]
&&
y.pageRequests[y.currentPage].busy
);
const samePageIdList =
samePage && x.ids[x.currentPage] === y.ids[y.currentPage];
return samePageIdList && samePageBusyState;
}

private createErrorObservable(pagination$: Observable<PaginationEntityState>) {
private createErrorObservable(
pagination$: Observable<PaginationEntityState>,
) {
return pagination$.pipe(
map(pagination => {
const currentPageRequest = this.getCurrentPageRequestInfo(pagination);
return !currentPageRequest.busy && currentPageRequest.error;
})
}),
);
}

private createFetchingObservable(pagination$: Observable<PaginationEntityState>) {
private createFetchingObservable(
pagination$: Observable<PaginationEntityState>,
) {
return pagination$.pipe(
map(pagination => {
const currentPageRequest = this.getCurrentPageRequestInfo(pagination);
return currentPageRequest.busy;
}),
distinctUntilChanged()
distinctUntilChanged(),
);
}
// ### Initialization methods end.

}