Feature/add support for column sorting to lazy loaded activities table (#2738)
* Add support for column sorting * Update changelog
This commit is contained in:
parent
ffb7cbff50
commit
b22edff16b
@ -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…
x
Reference in New Issue
Block a user