Browse Source

Add pagination logic

pull/2729/head
Thomas Kaul 2 years ago
parent
commit
f533f3e862
  1. 6
      apps/api/src/app/order/order.controller.ts
  2. 17
      apps/api/src/app/order/order.service.ts
  3. 56
      apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
  4. 50
      apps/client/src/app/services/data.service.ts
  5. 15
      libs/ui/src/lib/activities-table-lazy/activities-table-lazy.component.html
  6. 12
      libs/ui/src/lib/activities-table-lazy/activities-table-lazy.component.scss
  7. 8
      libs/ui/src/lib/activities-table-lazy/activities-table-lazy.component.ts
  8. 1
      libs/ui/src/lib/activities-table-lazy/activities-table-lazy.module.ts

6
apps/api/src/app/order/order.controller.ts

@ -24,7 +24,7 @@ import {
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { Order as OrderModel } from '@prisma/client';
import { Order as OrderModel, Prisma } from '@prisma/client';
import { parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@ -89,6 +89,8 @@ export class OrderController {
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId,
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('sortColumn') sortColumn?: string,
@Query('sortDirection') sortDirection?: Prisma.SortOrder,
@Query('skip') skip?: number,
@Query('tags') filterByTags?: string,
@Query('take') take?: number
@ -105,6 +107,8 @@ export class OrderController {
const activities = await this.orderService.getOrders({
filters,
sortColumn,
sortDirection,
userCurrency,
includeDrafts: true,
skip: isNaN(skip) ? undefined : skip,

17
apps/api/src/app/order/order.service.ts

@ -51,7 +51,7 @@ export class OrderService {
take?: number;
cursor?: Prisma.OrderWhereUniqueInput;
where?: Prisma.OrderWhereInput;
orderBy?: Prisma.OrderOrderByWithRelationInput;
orderBy?: Prisma.Enumerable<Prisma.OrderOrderByWithRelationInput>;
}): Promise<OrderWithAccount[]> {
const { include, skip, take, cursor, where, orderBy } = params;
@ -231,6 +231,8 @@ export class OrderService {
filters,
includeDrafts = false,
skip,
sortColumn,
sortDirection,
take = Number.MAX_SAFE_INTEGER,
types,
userCurrency,
@ -240,12 +242,17 @@ export class OrderService {
filters?: Filter[];
includeDrafts?: boolean;
skip?: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
take?: number;
types?: TypeOfOrder[];
userCurrency: string;
userId: string;
withExcludedAccounts?: boolean;
}): Promise<Activity[]> {
let orderBy: Prisma.Enumerable<Prisma.OrderOrderByWithRelationInput> = [
{ date: 'asc' }
];
const where: Prisma.OrderWhereInput = { userId };
const {
@ -307,6 +314,10 @@ export class OrderService {
};
}
if (sortColumn) {
orderBy = [{ [sortColumn]: sortDirection }];
}
if (types) {
where.OR = types.map((type) => {
return {
@ -319,6 +330,7 @@ export class OrderService {
return (
await this.orders({
orderBy,
skip,
take,
where,
@ -332,8 +344,7 @@ export class OrderService {
// eslint-disable-next-line @typescript-eslint/naming-convention
SymbolProfile: true,
tags: true
},
orderBy: { date: 'asc' }
}
})
)
.filter((order) => {

56
apps/client/src/app/pages/portfolio/activities/activities-page.component.ts

@ -16,7 +16,7 @@ import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { downloadAsFile } from '@ghostfolio/common/helper';
import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { DataSource, Order as OrderModel } from '@prisma/client';
import { DataSource, Order as OrderModel, Prisma } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, Subscription } from 'rxjs';
@ -42,6 +42,8 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit {
public pageIndex = 0;
public pageSize = DEFAULT_PAGE_SIZE;
public routeQueryParams: Subscription;
public sortColumn = 'date';
public sortDirection: Prisma.SortOrder = 'desc';
public user: User;
private unsubscribeSubject = new Subject<void>();
@ -109,26 +111,50 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit {
}
public fetchActivities() {
this.dataService
.fetchActivities({})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => {
this.activities = activities;
this.dataSource = new MatTableDataSource(activities);
if (this.user?.settings?.isExperimentalFeatures === true) {
this.dataService
.fetchActivities({
sortColumn: this.sortColumn,
sortDirection: this.sortDirection,
skip: this.pageIndex * this.pageSize,
take: this.pageSize
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => {
this.dataSource = new MatTableDataSource(activities);
if (
this.hasPermissionToCreateActivity &&
this.activities?.length <= 0
) {
this.router.navigate([], { queryParams: { createDialog: true } });
}
if (
this.hasPermissionToCreateActivity &&
this.activities?.length <= 0
) {
this.router.navigate([], { queryParams: { createDialog: true } });
}
this.changeDetectorRef.markForCheck();
});
} else {
this.dataService
.fetchActivities({})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => {
this.activities = activities;
if (
this.hasPermissionToCreateActivity &&
this.activities?.length <= 0
) {
this.router.navigate([], { queryParams: { createDialog: true } });
}
this.changeDetectorRef.markForCheck();
});
this.changeDetectorRef.markForCheck();
});
}
}
public onChangePage(page: PageEvent) {
this.pageIndex = page.pageIndex;
this.fetchActivities();
}
public onCloneActivity(aActivity: Activity) {

50
apps/client/src/app/services/data.service.ts

@ -38,7 +38,7 @@ import {
} from '@ghostfolio/common/interfaces';
import { filterGlobalPermissions } from '@ghostfolio/common/permissions';
import { AccountWithValue, DateRange, GroupBy } from '@ghostfolio/common/types';
import { DataSource, Order as OrderModel } from '@prisma/client';
import { DataSource, Order as OrderModel, Prisma } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { cloneDeep, groupBy, isNumber } from 'lodash';
import { Observable } from 'rxjs';
@ -149,23 +149,45 @@ export class DataService {
}
public fetchActivities({
filters
filters,
skip,
sortColumn,
sortDirection,
take
}: {
filters?: Filter[];
skip?: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
take?: number;
}): Observable<Activities> {
return this.http
.get<any>('/api/v1/order', {
params: this.buildFiltersAsQueryParams({ filters })
let params = this.buildFiltersAsQueryParams({ filters });
if (skip) {
params = params.append('skip', skip);
}
if (sortColumn) {
params = params.append('sortColumn', sortColumn);
}
if (sortDirection) {
params = params.append('sortDirection', sortDirection);
}
if (take) {
params = params.append('take', take);
}
return this.http.get<any>('/api/v1/order', { params }).pipe(
map(({ activities }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
activity.date = parseISO(activity.date);
}
return { activities };
})
.pipe(
map(({ activities }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
activity.date = parseISO(activity.date);
}
return { activities };
})
);
);
}
public fetchDividends({

15
libs/ui/src/lib/activities-table-lazy/activities-table-lazy.component.html

@ -65,14 +65,7 @@
</div>
<div class="activities">
<table
class="gf-table w-100"
mat-table
matSort
matSortActive="date"
matSortDirection="desc"
[dataSource]="dataSource"
>
<table class="gf-table w-100" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th *matHeaderCellDef class="px-1" mat-header-cell>
<mat-checkbox
@ -476,13 +469,11 @@
</div>
<mat-paginator
[length]="length"
[ngClass]="{
'd-none':
(isLoading && dataSource?.data.length === 0) ||
dataSource?.data.length <= pageSize
'd-none': isLoading && dataSource?.data.length === 0
}"
[pageSize]="pageSize"
[showFirstLastButtons]="true"
(page)="onChangePage($event)"
></mat-paginator>

12
libs/ui/src/lib/activities-table-lazy/activities-table-lazy.component.scss

@ -5,15 +5,11 @@
.activities {
overflow-x: auto;
}
.mat-mdc-table {
th {
::ng-deep {
.mat-sort-header-container {
justify-content: inherit;
}
}
}
::ng-deep {
.mat-mdc-paginator-range-label {
display: none;
}
}
}

8
libs/ui/src/lib/activities-table-lazy/activities-table-lazy.component.ts

@ -11,7 +11,6 @@ import {
ViewChild
} from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Router } from '@angular/router';
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
@ -21,7 +20,6 @@ import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types';
import { isUUID } from 'class-validator';
import { endOfToday, isAfter } from 'date-fns';
import { get } from 'lodash';
import { Subject, Subscription, takeUntil } from 'rxjs';
@Component({
@ -39,6 +37,7 @@ export class ActivitiesTableLazyComponent
@Input() hasPermissionToCreateActivity: boolean;
@Input() hasPermissionToExportActivities: boolean;
@Input() hasPermissionToOpenDetails = true;
@Input() length = Number.MAX_SAFE_INTEGER;
@Input() locale: string;
@Input() pageIndex: number;
@Input() pageSize = DEFAULT_PAGE_SIZE;
@ -59,7 +58,6 @@ export class ActivitiesTableLazyComponent
@Output() selectedActivities = new EventEmitter<Activity[]>();
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
public defaultDateFormat: string;
public displayedColumns = [];
@ -128,10 +126,6 @@ export class ActivitiesTableLazyComponent
}
if (this.dataSource) {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.dataSource.sortingDataAccessor = get;
this.isLoading = false;
}
}

1
libs/ui/src/lib/activities-table-lazy/activities-table-lazy.module.ts

@ -31,7 +31,6 @@ import { ActivitiesTableLazyComponent } from './activities-table-lazy.component'
MatCheckboxModule,
MatMenuModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
MatTooltipModule,
NgxSkeletonLoaderModule,

Loading…
Cancel
Save