Skip to content

Commit 88ec3ab

Browse files
susnuxprovokateurin
authored andcommitted
feat: add pagination to the frontend
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 39d6fe5 commit 88ec3ab

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed

src/settings/Api.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ export class Api {
1515
return generateUrl(`apps/groupfolders/${endpoint}`)
1616
}
1717

18-
async listFolders(): Promise<Folder[]> {
19-
const response = await axios.get<OCSResponse<Folder[]>>(this.getUrl('folders'))
18+
async listFolders(offset = 0, limit?: number): Promise<Folder[]> {
19+
const response = await axios.get<OCSResponse<Folder[]>>(this.getUrl('folders'), {
20+
params: {
21+
offset,
22+
limit,
23+
},
24+
})
2025
return Object.keys(response.data.ocs.data).map(id => response.data.ocs.data[id])
2126
}
2227

src/settings/App.scss

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,17 @@
178178
}
179179
}
180180
}
181-
}
181+
}
182+
183+
.groupfolders-pagination__list {
184+
display: flex;
185+
gap: var(--default-grid-baseline);
186+
justify-content: center;
187+
}
188+
189+
.groupfolders-pagination__button {
190+
height: var(--default-clickable-area);
191+
}
182192

183193
}
184194

src/settings/App.tsx

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const defaultQuotaOptions = {
2828
Unlimited: -3,
2929
}
3030

31+
const pageSize = 50
32+
3133
export type SortKey = 'mount_point' | 'quota' | 'groups' | 'acl';
3234

3335
export interface AppState {
@@ -45,6 +47,7 @@ export interface AppState {
4547
sortOrder: number;
4648
isAdminNextcloud: boolean;
4749
checkAppsInstalled: boolean;
50+
currentPage: number;
4851
}
4952

5053
export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Search.Core> {
@@ -66,10 +69,12 @@ export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Se
6669
sortOrder: 1,
6770
isAdminNextcloud: false,
6871
checkAppsInstalled: false,
72+
currentPage: 0,
6973
}
7074

7175
componentDidMount() {
72-
this.api.listFolders().then((folders) => {
76+
// list first pageSize + 1 folders so we know if there are more pages
77+
this.api.listFolders(0, pageSize + 1).then((folders) => {
7378
this.setState({ folders })
7479
})
7580
this.api.listGroups().then((groups) => {
@@ -169,6 +174,21 @@ export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Se
169174
this.api.setACL(folder.id, acl)
170175
}
171176

177+
async goToPage(page: number) {
178+
const loadedPage = Math.floor(this.state.folders.length / pageSize)
179+
if (loadedPage <= page) {
180+
const folders = await this.api.listFolders(this.state.folders.length, (page + 1) * pageSize - this.state.folders.length + 1)
181+
this.setState({
182+
folders: [...this.state.folders, ...folders],
183+
currentPage: page,
184+
})
185+
} else {
186+
this.setState({
187+
currentPage: page,
188+
})
189+
}
190+
}
191+
172192
onSortClick = (sort: SortKey) => {
173193
if (this.state.sort === sort) {
174194
this.setState({ sortOrder: -this.state.sortOrder })
@@ -213,7 +233,7 @@ export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Se
213233
if (this.state.filter === '') {
214234
return true
215235
}
216-
return folder.mount_point.toLowerCase().indexOf(this.state.filter.toLowerCase()) !== -1
236+
return folder.mount_point.toLowerCase().includes(this.state.filter.toLowerCase())
217237
})
218238
.sort((a, b) => {
219239
switch (this.state.sort) {
@@ -239,6 +259,7 @@ export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Se
239259
}
240260
return 0
241261
})
262+
.slice(this.state.currentPage * pageSize, this.state.currentPage * pageSize + pageSize)
242263
.map(folder => {
243264
const id = folder.id
244265
return <tr key={id}>
@@ -361,6 +382,60 @@ export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Se
361382
</tr>
362383
</FlipMove>
363384
</table>
385+
<nav className="groupfolders-pagination" aria-label={t('groupfolders', 'Pagination of team folders')}>
386+
<ul className="groupfolders-pagination__list">
387+
<li>
388+
<button
389+
aria-label={t('groupfolders', 'Previous')}
390+
className="groupfolders-pagination__button"
391+
disabled={this.state.currentPage === 0}
392+
title={t('groupfolders', 'Previous')}
393+
onClick={() => this.goToPage(this.state.currentPage - 1)}></button>
394+
</li>
395+
{
396+
// show the "1" button if we are not on the first page
397+
this.state.currentPage > 0 && <li><button onClick={() => this.goToPage(0)}>1</button></li>
398+
}
399+
{
400+
// show the ellipsis button if there are more than 2 pages before the current
401+
this.state.currentPage > 2 && <li><button disabled>&#8230;</button></li>}
402+
{
403+
// show the page right before the current - if there is such a page
404+
this.state.currentPage > 1 && <li><button onClick={() => this.goToPage(this.state.currentPage - 1)}>{this.state.currentPage}</button></li>
405+
}
406+
{ /* the current page as a button */}
407+
<li><button aria-current="page" aria-disabled className="primary">{this.state.currentPage + 1}</button></li>
408+
{
409+
// show the next page if it exists (we know at least that the next exists or not)
410+
(this.state.currentPage + 1) < (this.state.folders.length / pageSize)
411+
&& <li>
412+
<button onClick={() => this.goToPage(this.state.currentPage + 1)}>{this.state.currentPage + 2}</button>
413+
</li>
414+
}
415+
{
416+
// If we know more than two next pages exist we show the ellipsis for the intermediate pages
417+
(this.state.currentPage + 3) < (this.state.folders.length / pageSize)
418+
&& <li>
419+
<button disabled>&#8230;</button>
420+
</li>
421+
}
422+
{
423+
// If more than one next page exist we show the last page as a button
424+
(this.state.currentPage + 2) < (this.state.folders.length / pageSize)
425+
&& <li>
426+
<button onClick={() => this.goToPage(Math.floor(this.state.folders.length / pageSize))}>{Math.floor(this.state.folders.length / pageSize) + 1}</button>
427+
</li>
428+
}
429+
<li>
430+
<button
431+
aria-label={t('groupfolders', 'Next')}
432+
className="groupfolders-pagination__button"
433+
disabled={this.state.currentPage >= Math.floor(this.state.folders.length / pageSize)}
434+
title={t('groupfolders', 'Next')}
435+
onClick={() => this.goToPage(this.state.currentPage + 1)}></button>
436+
</li>
437+
</ul>
438+
</nav>
364439
</div>
365440
}
366441

0 commit comments

Comments
 (0)