Browse Source

Add pagination to activities table (#1404)

* Add pagination to activities table
pull/1415/head
Yash Solanki 2 years ago
committed by GitHub
parent
commit
901c997908
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/client/src/app/pages/portfolio/transactions/transactions-page.html
  2. 12
      apps/client/src/styles.scss
  3. 1
      libs/common/src/lib/config.ts
  4. 30
      libs/ui/src/lib/activities-table/activities-table.component.html
  5. 36
      libs/ui/src/lib/activities-table/activities-table.component.ts
  6. 2
      libs/ui/src/lib/activities-table/activities-table.module.ts

2
apps/client/src/app/pages/portfolio/transactions/transactions-page.html

@ -29,8 +29,8 @@
class="align-items-center d-flex justify-content-center" class="align-items-center d-flex justify-content-center"
color="primary" color="primary"
mat-fab mat-fab
[routerLink]="[]"
[queryParams]="{ createDialog: true }" [queryParams]="{ createDialog: true }"
[routerLink]="[]"
> >
<ion-icon name="add-outline" size="large"></ion-icon> <ion-icon name="add-outline" size="large"></ion-icon>
</a> </a>

12
apps/client/src/styles.scss

@ -90,6 +90,10 @@ body {
} }
} }
.mat-paginator {
background-color: rgba(var(--palette-foreground-base-dark), 0.02);
}
.svgMap-tooltip { .svgMap-tooltip {
background: var(--dark-background); background: var(--dark-background);
@ -220,6 +224,14 @@ ngx-skeleton-loader {
} }
} }
.mat-paginator {
background-color: rgba(var(--palette-foreground-base-light), 0.02);
.mat-paginator-page-size {
display: none;
}
}
.no-min-width { .no-min-width {
min-width: unset !important; min-width: unset !important;
} }

1
libs/common/src/lib/config.ts

@ -40,6 +40,7 @@ export const DATA_GATHERING_QUEUE_PRIORITY_HIGH = 1;
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
export const DEFAULT_LANGUAGE_CODE = 'en'; export const DEFAULT_LANGUAGE_CODE = 'en';
export const DEFAULT_PAGE_SIZE = 50;
export const GATHER_ASSET_PROFILE_PROCESS = 'GATHER_ASSET_PROFILE'; export const GATHER_ASSET_PROFILE_PROCESS = 'GATHER_ASSET_PROFILE';
export const GATHER_ASSET_PROFILE_PROCESS_OPTIONS: JobOptions = { export const GATHER_ASSET_PROFILE_PROCESS_OPTIONS: JobOptions = {

30
libs/ui/src/lib/activities-table/activities-table.component.html

@ -9,10 +9,10 @@
<div class="activities"> <div class="activities">
<table <table
class="gf-table w-100" class="gf-table w-100"
mat-table
matSort matSort
matSortActive="date" matSortActive="date"
matSortDirection="desc" matSortDirection="desc"
mat-table
[dataSource]="dataSource" [dataSource]="dataSource"
> >
<ng-container matColumnDef="count"> <ng-container matColumnDef="count">
@ -27,7 +27,11 @@
class="d-none d-lg-table-cell px-1 text-right" class="d-none d-lg-table-cell px-1 text-right"
mat-cell mat-cell
> >
{{ dataSource.data.length - i }} {{
dataSource.data.length > pageSize
? dataSource.data.length - pageSize * pageIndex - i
: dataSource.data.length - i
}}
</td> </td>
<td <td
*matFooterCellDef *matFooterCellDef
@ -51,7 +55,7 @@
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header> <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Type</ng-container> <ng-container i18n>Type</ng-container>
</th> </th>
<td *matCellDef="let element" mat-cell class="px-1"> <td *matCellDef="let element" class="px-1" mat-cell>
<div <div
class="d-inline-flex p-1 type-badge" class="d-inline-flex p-1 type-badge"
[ngClass]="{ [ngClass]="{
@ -389,6 +393,10 @@
<tr <tr
*matRowDef="let row; columns: displayedColumns" *matRowDef="let row; columns: displayedColumns"
mat-row mat-row
[ngClass]="{
'cursor-pointer':
hasPermissionToOpenDetails && !row.isDraft && row.type !== 'ITEM'
}"
(click)=" (click)="
hasPermissionToOpenDetails && hasPermissionToOpenDetails &&
!row.isDraft && !row.isDraft &&
@ -398,10 +406,6 @@
symbol: row.SymbolProfile.symbol symbol: row.SymbolProfile.symbol
}) })
" "
[ngClass]="{
'cursor-pointer':
hasPermissionToOpenDetails && !row.isDraft && row.type !== 'ITEM'
}"
></tr> ></tr>
<tr <tr
*matFooterRowDef="displayedColumns" *matFooterRowDef="displayedColumns"
@ -411,6 +415,18 @@
</table> </table>
</div> </div>
<mat-paginator
showFirstLastButtons="true"
[ngClass]="{
'd-none':
isLoading ||
dataSource.data.length === 0 ||
dataSource.data.length <= pageSize
}"
[pageSize]="pageSize"
(page)="onChangePage($event)"
></mat-paginator>
<ngx-skeleton-loader <ngx-skeleton-loader
*ngIf="isLoading" *ngIf="isLoading"
animation="pulse" animation="pulse"

36
libs/ui/src/lib/activities-table/activities-table.component.ts

@ -8,10 +8,12 @@ import {
Output, Output,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort'; import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { getDateFormatString } from '@ghostfolio/common/helper'; import { getDateFormatString } from '@ghostfolio/common/helper';
import { Filter, UniqueAsset } from '@ghostfolio/common/interfaces'; import { Filter, UniqueAsset } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types'; import { OrderWithAccount } from '@ghostfolio/common/types';
@ -37,6 +39,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
@Input() hasPermissionToImportActivities: boolean; @Input() hasPermissionToImportActivities: boolean;
@Input() hasPermissionToOpenDetails = true; @Input() hasPermissionToOpenDetails = true;
@Input() locale: string; @Input() locale: string;
@Input() pageSize = DEFAULT_PAGE_SIZE;
@Input() showActions: boolean; @Input() showActions: boolean;
@Input() showSymbolColumn = true; @Input() showSymbolColumn = true;
@ -47,6 +50,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
@Output() exportDrafts = new EventEmitter<string[]>(); @Output() exportDrafts = new EventEmitter<string[]>();
@Output() import = new EventEmitter<void>(); @Output() import = new EventEmitter<void>();
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
public allFilters: Filter[]; public allFilters: Filter[];
@ -59,6 +63,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
public isAfter = isAfter; public isAfter = isAfter;
public isLoading = true; public isLoading = true;
public isUUID = isUUID; public isUUID = isUUID;
public pageIndex = 0;
public placeholder = ''; public placeholder = '';
public routeQueryParams: Subscription; public routeQueryParams: Subscription;
public searchKeywords: string[] = []; public searchKeywords: string[] = [];
@ -119,12 +124,20 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
} }
return contains; return contains;
}; };
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort; this.dataSource.sort = this.sort;
this.updateFilters(); this.updateFilters();
} }
} }
public onChangePage(page: PageEvent) {
this.pageIndex = page.pageIndex;
this.totalFees = this.getTotalFees();
this.totalValue = this.getTotalValue();
}
public onCloneActivity(aActivity: OrderWithAccount) { public onCloneActivity(aActivity: OrderWithAccount) {
this.activityToClone.emit(aActivity); this.activityToClone.emit(aActivity);
} }
@ -231,6 +244,21 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
return Object.values(fieldValueMap); return Object.values(fieldValueMap);
} }
private getPaginatedData() {
if (this.dataSource.data.length > this.pageSize) {
const sortedData = this.dataSource.sortData(
this.dataSource.filteredData,
this.dataSource.sort
);
return sortedData.slice(
this.pageIndex * this.pageSize,
(this.pageIndex + 1) * this.pageSize
);
}
return this.dataSource.filteredData;
}
private getSearchableFieldValues(activities: OrderWithAccount[]): Filter[] { private getSearchableFieldValues(activities: OrderWithAccount[]): Filter[] {
const fieldValueMap: { [id: string]: Filter } = {}; const fieldValueMap: { [id: string]: Filter } = {};
@ -243,8 +271,8 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
private getTotalFees() { private getTotalFees() {
let totalFees = new Big(0); let totalFees = new Big(0);
const paginatedData = this.getPaginatedData();
for (const activity of this.dataSource.filteredData) { for (const activity of paginatedData) {
if (isNumber(activity.feeInBaseCurrency)) { if (isNumber(activity.feeInBaseCurrency)) {
totalFees = totalFees.plus(activity.feeInBaseCurrency); totalFees = totalFees.plus(activity.feeInBaseCurrency);
} else { } else {
@ -257,8 +285,8 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
private getTotalValue() { private getTotalValue() {
let totalValue = new Big(0); let totalValue = new Big(0);
const paginatedData = this.getPaginatedData();
for (const activity of this.dataSource.filteredData) { for (const activity of paginatedData) {
if (isNumber(activity.valueInBaseCurrency)) { if (isNumber(activity.valueInBaseCurrency)) {
if (activity.type === 'BUY' || activity.type === 'ITEM') { if (activity.type === 'BUY' || activity.type === 'ITEM') {
totalValue = totalValue.plus(activity.valueInBaseCurrency); totalValue = totalValue.plus(activity.valueInBaseCurrency);

2
libs/ui/src/lib/activities-table/activities-table.module.ts

@ -2,6 +2,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 { MatSortModule } from '@angular/material/sort'; import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
@ -26,6 +27,7 @@ import { ActivitiesTableComponent } from './activities-table.component';
GfValueModule, GfValueModule,
MatButtonModule, MatButtonModule,
MatMenuModule, MatMenuModule,
MatPaginatorModule,
MatSortModule, MatSortModule,
MatTableModule, MatTableModule,
NgxSkeletonLoaderModule, NgxSkeletonLoaderModule,

Loading…
Cancel
Save