Feature/add pagination to users table (#4092)

* Add pagination to users table

* Update changelog
pull/4115/head
Ayush2198-source 3 weeks ago committed by GitHub
parent dbfac54af9
commit c85a1be3cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- Added pagination to the users table of the admin control panel
## 2.125.0 - 2024-11-30 ## 2.125.0 - 2024-11-30
### Changed ### Changed

@ -4,11 +4,19 @@ import { AdminService } from '@ghostfolio/client/services/admin.service';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper'; import { getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper';
import { AdminUsers, InfoItem, User } from '@ghostfolio/common/interfaces'; import { AdminUsers, InfoItem, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import {
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { import {
differenceInSeconds, differenceInSeconds,
@ -24,6 +32,8 @@ import { takeUntil } from 'rxjs/operators';
templateUrl: './admin-users.html' templateUrl: './admin-users.html'
}) })
export class AdminUsersComponent implements OnDestroy, OnInit { export class AdminUsersComponent implements OnDestroy, OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
public dataSource = new MatTableDataSource<AdminUsers['users'][0]>(); public dataSource = new MatTableDataSource<AdminUsers['users'][0]>();
public defaultDateFormat: string; public defaultDateFormat: string;
public displayedColumns: string[] = []; public displayedColumns: string[] = [];
@ -32,6 +42,8 @@ export class AdminUsersComponent implements OnDestroy, OnInit {
public hasPermissionToImpersonateAllUsers: boolean; public hasPermissionToImpersonateAllUsers: boolean;
public info: InfoItem; public info: InfoItem;
public isLoading = false; public isLoading = false;
public pageSize = DEFAULT_PAGE_SIZE;
public totalItems = 0;
public user: User; public user: User;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -137,19 +149,33 @@ export class AdminUsersComponent implements OnDestroy, OnInit {
window.location.reload(); window.location.reload();
} }
public onChangePage(page: PageEvent) {
this.fetchUsers({
pageIndex: page.pageIndex
});
}
public ngOnDestroy() { public ngOnDestroy() {
this.unsubscribeSubject.next(); this.unsubscribeSubject.next();
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();
} }
private fetchUsers() { private fetchUsers({ pageIndex }: { pageIndex: number } = { pageIndex: 0 }) {
this.isLoading = true; this.isLoading = true;
if (pageIndex === 0 && this.paginator) {
this.paginator.pageIndex = 0;
}
this.adminService this.adminService
.fetchUsers() .fetchUsers({
skip: pageIndex * this.pageSize,
take: this.pageSize
})
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ users }) => { .subscribe(({ count, users }) => {
this.dataSource = new MatTableDataSource(users); this.dataSource = new MatTableDataSource(users);
this.totalItems = count;
this.isLoading = false; this.isLoading = false;

@ -267,6 +267,17 @@
></tr> ></tr>
</table> </table>
</div> </div>
<mat-paginator
[length]="totalItems"
[ngClass]="{
'd-none': (isLoading && totalItems === 0) || totalItems <= pageSize
}"
[pageSize]="pageSize"
[showFirstLastButtons]="true"
(page)="onChangePage($event)"
/>
@if (isLoading) { @if (isLoading) {
<ngx-skeleton-loader <ngx-skeleton-loader
animation="pulse" animation="pulse"

@ -5,6 +5,7 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@ -19,6 +20,7 @@ import { AdminUsersComponent } from './admin-users.component';
GfValueComponent, GfValueComponent,
MatButtonModule, MatButtonModule,
MatMenuModule, MatMenuModule,
MatPaginatorModule,
MatTableModule, MatTableModule,
NgxSkeletonLoaderModule NgxSkeletonLoaderModule
], ],

@ -10,6 +10,7 @@ import {
HEADER_KEY_TOKEN, HEADER_KEY_TOKEN,
PROPERTY_API_KEY_GHOSTFOLIO PROPERTY_API_KEY_GHOSTFOLIO
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { import {
AssetProfileIdentifier, AssetProfileIdentifier,
@ -179,10 +180,17 @@ export class AdminService {
return this.http.get<Tag[]>('/api/v1/tag'); return this.http.get<Tag[]>('/api/v1/tag');
} }
public fetchUsers() { public fetchUsers({
skip,
take = DEFAULT_PAGE_SIZE
}: {
skip?: number;
take?: number;
}) {
let params = new HttpParams(); let params = new HttpParams();
params = params.append('take', 30); params = params.append('skip', skip);
params = params.append('take', take);
return this.http.get<AdminUsers>('/api/v1/admin/user', { params }); return this.http.get<AdminUsers>('/api/v1/admin/user', { params });
} }

Loading…
Cancel
Save