Feature/add support for column sorting to lazy loaded activities table (#2738)

* Add support for column sorting

* Update changelog
pull/2743/head
Thomas Kaul 6 months ago committed by GitHub
parent ffb7cbff50
commit b22edff16b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added support for column sorting to the lazy-loaded activities table on the portfolio activities page (experimental)
- Extended the benchmarks of the markets overview by the current market condition (all time high)
### Changed

@ -9,7 +9,7 @@ import {
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSort, Sort } from '@angular/material/sort';
import { MatSort, Sort, SortDirection } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
import { AdminService } from '@ghostfolio/client/services/admin.service';
@ -19,7 +19,7 @@ import { getDateFormatString } from '@ghostfolio/common/helper';
import { Filter, UniqueAsset, User } from '@ghostfolio/common/interfaces';
import { AdminMarketDataItem } from '@ghostfolio/common/interfaces/admin-market-data.interface';
import { translate } from '@ghostfolio/ui/i18n';
import { AssetSubClass, DataSource, Prisma } from '@prisma/client';
import { AssetSubClass, DataSource } from '@prisma/client';
import { isUUID } from 'class-validator';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
@ -160,7 +160,7 @@ export class AdminMarketDataComponent
this.loadData({
sortColumn,
sortDirection: <Prisma.SortOrder>direction,
sortDirection: direction,
pageIndex: this.paginator.pageIndex
});
}
@ -175,7 +175,7 @@ export class AdminMarketDataComponent
this.loadData({
pageIndex: page.pageIndex,
sortColumn: this.sort.active,
sortDirection: <Prisma.SortOrder>this.sort.direction
sortDirection: this.sort.direction
});
}
@ -262,7 +262,7 @@ export class AdminMarketDataComponent
}: {
pageIndex: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
sortDirection?: SortDirection;
} = { pageIndex: 0 }
) {
this.isLoading = true;

@ -1,6 +1,7 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { PageEvent } from '@angular/material/paginator';
import { Sort, SortDirection } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
@ -16,7 +17,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, Prisma } from '@prisma/client';
import { DataSource, Order as OrderModel } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, Subscription } from 'rxjs';
@ -43,7 +44,7 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit {
public pageSize = DEFAULT_PAGE_SIZE;
public routeQueryParams: Subscription;
public sortColumn = 'date';
public sortDirection: Prisma.SortOrder = 'desc';
public sortDirection: SortDirection = 'desc';
public totalItems: number;
public user: User;
@ -261,6 +262,14 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit {
});
}
public onSortChanged({ active, direction }: Sort) {
this.pageIndex = 0;
this.sortColumn = active;
this.sortDirection = direction;
this.fetchActivities();
}
public onUpdateActivity(aActivity: OrderModel) {
this.router.navigate([], {
queryParams: { activityId: aActivity.id, editDialog: true }

@ -13,6 +13,8 @@
[pageIndex]="pageIndex"
[pageSize]="pageSize"
[showActions]="!hasImpersonationId && hasPermissionToDeleteActivity && !user.settings.isRestrictedView"
[sortColumn]="sortColumn"
[sortDirection]="sortDirection"
[totalItems]="totalItems"
(activityDeleted)="onDeleteActivity($event)"
(activityToClone)="onCloneActivity($event)"
@ -23,6 +25,7 @@
(import)="onImport()"
(importDividends)="onImportDividends()"
(pageChanged)="onChangePage($event)"
(sortChanged)="onSortChanged($event)"
></gf-activities-table-lazy>
<gf-activities-table
*ngIf="user?.settings?.isExperimentalFeatures !== true"

@ -1,5 +1,6 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { SortDirection } from '@angular/material/sort';
import { UpdateAssetProfileDto } from '@ghostfolio/api/app/admin/update-asset-profile.dto';
import { UpdateBulkMarketDataDto } from '@ghostfolio/api/app/admin/update-bulk-market-data.dto';
import { CreatePlatformDto } from '@ghostfolio/api/app/platform/create-platform.dto';
@ -17,7 +18,7 @@ import {
Filter,
UniqueAsset
} from '@ghostfolio/common/interfaces';
import { DataSource, MarketData, Platform, Prisma, Tag } from '@prisma/client';
import { DataSource, MarketData, Platform, Tag } from '@prisma/client';
import { JobStatus } from 'bull';
import { format, parseISO } from 'date-fns';
import { Observable, map } from 'rxjs';
@ -84,7 +85,7 @@ export class AdminService {
filters?: Filter[];
skip?: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
sortDirection?: SortDirection;
take: number;
}) {
let params = this.dataService.buildFiltersAsQueryParams({ filters });

@ -1,5 +1,6 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { SortDirection } from '@angular/material/sort';
import { CreateAccessDto } from '@ghostfolio/api/app/access/create-access.dto';
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { TransferBalanceDto } from '@ghostfolio/api/app/account/transfer-balance.dto';
@ -38,7 +39,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, Prisma } from '@prisma/client';
import { DataSource, Order as OrderModel } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { cloneDeep, groupBy, isNumber } from 'lodash';
import { Observable } from 'rxjs';
@ -158,7 +159,7 @@ export class DataService {
filters?: Filter[];
skip?: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
sortDirection?: SortDirection;
take?: number;
}): Observable<Activities> {
let params = this.buildFiltersAsQueryParams({ filters });

@ -65,7 +65,14 @@
</div>
<div class="activities">
<table class="gf-table w-100" mat-table [dataSource]="dataSource">
<table
class="gf-table w-100"
mat-table
matSort
[dataSource]="dataSource"
[matSortActive]="sortColumn"
[matSortDirection]="sortDirection"
>
<ng-container matColumnDef="select">
<th *matHeaderCellDef class="px-1" mat-header-cell>
<mat-checkbox
@ -118,12 +125,7 @@
</ng-container>
<ng-container matColumnDef="nameWithSymbol">
<th
*matHeaderCellDef
class="px-1"
mat-header-cell
mat-sort-header="SymbolProfile.symbol"
>
<th *matHeaderCellDef class="px-1" mat-header-cell>
<ng-container i18n>Name</ng-container>
</th>
<td *matCellDef="let element" class="line-height-1 px-1" mat-cell>
@ -243,7 +245,6 @@
*matHeaderCellDef
class="d-none d-lg-table-cell justify-content-end px-1"
mat-header-cell
mat-sort-header
>
<ng-container i18n>Value</ng-container>
</th>
@ -263,12 +264,7 @@
</ng-container>
<ng-container matColumnDef="currency">
<th
*matHeaderCellDef
class="d-none d-lg-table-cell px-1"
mat-header-cell
mat-sort-header="SymbolProfile.currency"
>
<th *matHeaderCellDef class="d-none d-lg-table-cell px-1" mat-header-cell>
<ng-container i18n>Currency</ng-container>
</th>
<td
@ -285,7 +281,6 @@
*matHeaderCellDef
class="d-lg-none d-xl-none justify-content-end px-1"
mat-header-cell
mat-sort-header
>
<ng-container i18n>Value</ng-container>
</th>
@ -301,12 +296,7 @@
</ng-container>
<ng-container matColumnDef="account">
<th
*matHeaderCellDef
class="px-1"
mat-header-cell
mat-sort-header="Account.name"
>
<th *matHeaderCellDef class="px-1" mat-header-cell>
<span class="d-none d-lg-block" i18n>Account</span>
</th>
<td *matCellDef="let element" class="px-1" mat-cell>
@ -473,7 +463,9 @@
[ngClass]="{
'd-none': (isLoading && totalItems === 0) || totalItems <= pageSize
}"
[pageIndex]="pageIndex"
[pageSize]="pageSize"
[showFirstLastButtons]="true"
(page)="onChangePage($event)"
></mat-paginator>

@ -1,5 +1,6 @@
import { SelectionModel } from '@angular/cdk/collections';
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
EventEmitter,
@ -11,6 +12,7 @@ import {
ViewChild
} from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSort, Sort, SortDirection } 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';
@ -29,7 +31,7 @@ import { Subject, Subscription, takeUntil } from 'rxjs';
templateUrl: './activities-table-lazy.component.html'
})
export class ActivitiesTableLazyComponent
implements OnChanges, OnDestroy, OnInit
implements AfterViewInit, OnChanges, OnDestroy, OnInit
{
@Input() baseCurrency: string;
@Input() dataSource: MatTableDataSource<Activity>;
@ -44,6 +46,8 @@ export class ActivitiesTableLazyComponent
@Input() showCheckbox = false;
@Input() showFooter = true;
@Input() showNameColumn = true;
@Input() sortColumn: string;
@Input() sortDirection: SortDirection;
@Input() totalItems = Number.MAX_SAFE_INTEGER;
@Output() activityDeleted = new EventEmitter<string>();
@ -56,8 +60,10 @@ export class ActivitiesTableLazyComponent
@Output() importDividends = new EventEmitter<UniqueAsset>();
@Output() pageChanged = new EventEmitter<PageEvent>();
@Output() selectedActivities = new EventEmitter<Activity[]>();
@Output() sortChanged = new EventEmitter<Sort>();
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
public defaultDateFormat: string;
public displayedColumns = [];
@ -86,6 +92,12 @@ export class ActivitiesTableLazyComponent
}
}
public ngAfterViewInit() {
this.sort.sortChange.subscribe((value: Sort) => {
this.sortChanged.emit(value);
});
}
public areAllRowsSelected() {
const numSelectedRows = this.selectedRows.selected.length;
const numTotalRows = this.dataSource.data.length;

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

Loading…
Cancel
Save