Skip to content

Commit

Permalink
feat: improved page navigation for users list (#3741)
Browse files Browse the repository at this point in the history
* feat: add first and last page buttons

* feat: add textbox-based page navigation

* feat: add query parameter page navigation
  • Loading branch information
davwheat authored Feb 21, 2023
1 parent 0da069b commit 408a92b
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 8 deletions.
105 changes: 99 additions & 6 deletions framework/core/js/src/admin/components/UserListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import icon from '../../common/helpers/icon';
import listItems from '../../common/helpers/listItems';

import type User from '../../common/models/User';
import type { IPageAttrs } from '../../common/components/Page';

import ItemList from '../../common/utils/ItemList';
import classList from '../../common/utils/classList';
Expand Down Expand Up @@ -45,6 +46,11 @@ export default class UserListPage extends AdminPage {
*/
private pageNumber: number = 0;

/**
* Page number being loaded. Zero-indexed.
*/
private loadingPageNumber: number = 0;

/**
* Total number of forum users.
*
Expand Down Expand Up @@ -77,12 +83,28 @@ export default class UserListPage extends AdminPage {

private isLoadingPage: boolean = false;

oninit(vnode: Mithril.Vnode<IPageAttrs, this>) {
super.oninit(vnode);

// Get page query value from URL
const page = parseInt(m.route.param('page'));

if (isNaN(page) || page < 1) {
this.setPageNumberInUrl(1);
this.pageNumber = 0;
} else {
this.pageNumber = page - 1;
}

this.loadingPageNumber = this.pageNumber;
}

/**
* Component to render.
*/
content() {
if (typeof this.pageData === 'undefined') {
this.loadPage(0);
this.loadPage(this.pageNumber);

return [
<section class="UserListPage-grid UserListPage-grid--loading">
Expand Down Expand Up @@ -149,6 +171,13 @@ export default class UserListPage extends AdminPage {
{this.isLoadingPage && <LoadingIndicator size="large" />}
</section>,
<nav class="UserListPage-gridPagination">
<Button
disabled={this.pageNumber === 0}
title={app.translator.trans('core.admin.users.pagination.first_page_button')}
onclick={this.goToPage.bind(this, 1)}
icon="fas fa-step-backward"
className="Button Button--icon UserListPage-firstPageBtn"
/>
<Button
disabled={this.pageNumber === 0}
title={app.translator.trans('core.admin.users.pagination.back_button')}
Expand All @@ -158,7 +187,38 @@ export default class UserListPage extends AdminPage {
/>
<span class="UserListPage-pageNumber">
{app.translator.trans('core.admin.users.pagination.page_counter', {
current: this.pageNumber + 1,
current: (
<input
type="text"
value={this.loadingPageNumber + 1}
aria-label={extractText(app.translator.trans('core.admin.users.pagination.go_to_page_textbox_a11y_label'))}
autocomplete="off"
className="FormControl UserListPage-pageNumberInput"
onchange={(e: InputEvent) => {
const target = e.target as HTMLInputElement;
let pageNumber = parseInt(target.value);

if (isNaN(pageNumber)) {
// Invalid value, reset to current page
target.value = (this.pageNumber + 1).toString();
return;
}

if (pageNumber < 1) {
// Lower constraint
pageNumber = 1;
} else if (pageNumber > this.getTotalPageCount()) {
// Upper constraint
pageNumber = this.getTotalPageCount();
}

target.value = pageNumber.toString();

this.goToPage(pageNumber);
}}
/>
),
currentNum: this.pageNumber + 1,
total: this.getTotalPageCount(),
})}
</span>
Expand All @@ -169,6 +229,13 @@ export default class UserListPage extends AdminPage {
icon="fas fa-chevron-right"
className="Button Button--icon UserListPage-nextBtn"
/>
<Button
disabled={!this.moreData}
title={app.translator.trans('core.admin.users.pagination.last_page_button')}
onclick={this.goToPage.bind(this, this.getTotalPageCount())}
icon="fas fa-step-forward"
className="Button Button--icon UserListPage-lastPageBtn"
/>
</nav>,
];
}
Expand Down Expand Up @@ -347,11 +414,14 @@ export default class UserListPage extends AdminPage {
*
* Uses the `this.numPerPage` as the response limit, and automatically calculates the offset required from `pageNumber`.
*
* @param pageNumber The page number to load and display
* @param pageNumber The **zero-based** page number to load and display
*/
async loadPage(pageNumber: number) {
if (pageNumber < 0) pageNumber = 0;

this.loadingPageNumber = pageNumber;
this.setPageNumberInUrl(pageNumber + 1);

app.store
.find<User[]>('users', {
filter: { q: this.query },
Expand All @@ -369,9 +439,16 @@ export default class UserListPage extends AdminPage {
// @ts-ignore
delete data.payload;

this.pageData = data;
this.pageNumber = pageNumber;
this.isLoadingPage = false;
const lastPage = this.getTotalPageCount();

if (pageNumber > lastPage) {
this.loadPage(lastPage - 1);
} else {
this.pageData = data;
this.pageNumber = pageNumber;
this.loadingPageNumber = pageNumber;
this.isLoadingPage = false;
}

m.redraw();
})
Expand All @@ -390,4 +467,20 @@ export default class UserListPage extends AdminPage {
this.isLoadingPage = true;
this.loadPage(this.pageNumber - 1);
}

/**
* @param page The **1-based** page number
*/
goToPage(page: number) {
this.isLoadingPage = true;
this.loadPage(page - 1);
}

private setPageNumberInUrl(pageNumber: number) {
const search = window.location.hash.split('?', 2);
const params = new URLSearchParams(search?.[1] ?? '');

params.set('page', `${pageNumber}`);
window.location.hash = search?.[0] + '?' + params.toString();
}
}
17 changes: 15 additions & 2 deletions framework/core/less/admin/UsersListPage.less
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,24 @@
}

&-gridPagination {
display: flex;
display: grid;
grid-template-columns: auto auto 1fr auto auto;
gap: 8px;
align-items: center;
justify-content: space-between;
justify-content: center;
margin-top: 16px;
}

&-pageNumber {
text-align: center;
}

&-pageNumberInput {
display: inline-block;
margin: 0 8px;
width: auto;
max-width: 80px;
}
}

// Handles styling of default UserList columns
Expand Down
3 changes: 3 additions & 0 deletions framework/core/locale/core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ core:

pagination:
back_button: Previous page
first_button: Go to first page
go_to_page_textbox_a11y_label: Go directly to page number
last_button: Go to last page
next_button: Next page
page_counter: Page {current} of {total}

Expand Down

0 comments on commit 408a92b

Please sign in to comment.