Feature/add lazy loaded activities table to account detail dialog (#2752)
* Add lazy-loaded activities table * Update changelog
This commit is contained in:
parent
4547c5da1d
commit
a10d9cb6ba
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- Introduced the lazy-loaded activities table to the account detail dialog (experimental)
|
||||||
- Introduced the lazy-loaded activities table to the position detail dialog (experimental)
|
- Introduced the lazy-loaded activities table to the position detail dialog (experimental)
|
||||||
- Improved the font weight in the value component
|
- Improved the font weight in the value component
|
||||||
- Improved the language localization for Türkçe (`tr`)
|
- Improved the language localization for Türkçe (`tr`)
|
||||||
|
@ -7,6 +7,8 @@ import {
|
|||||||
OnInit
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { Sort, SortDirection } from '@angular/material/sort';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
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';
|
||||||
@ -16,6 +18,7 @@ import {
|
|||||||
HistoricalDataItem,
|
HistoricalDataItem,
|
||||||
User
|
User
|
||||||
} from '@ghostfolio/common/interfaces';
|
} from '@ghostfolio/common/interfaces';
|
||||||
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { OrderWithAccount } from '@ghostfolio/common/types';
|
import { OrderWithAccount } from '@ghostfolio/common/types';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import { format, parseISO } from 'date-fns';
|
import { format, parseISO } from 'date-fns';
|
||||||
@ -24,7 +27,6 @@ import { Subject } from 'rxjs';
|
|||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import { AccountDetailDialogParams } from './interfaces/interfaces';
|
import { AccountDetailDialogParams } from './interfaces/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
host: { class: 'd-flex flex-column h-100' },
|
host: { class: 'd-flex flex-column h-100' },
|
||||||
@ -38,6 +40,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
public activities: OrderWithAccount[];
|
public activities: OrderWithAccount[];
|
||||||
public balance: number;
|
public balance: number;
|
||||||
public currency: string;
|
public currency: string;
|
||||||
|
public dataSource: MatTableDataSource<OrderWithAccount>;
|
||||||
public equity: number;
|
public equity: number;
|
||||||
public hasImpersonationId: boolean;
|
public hasImpersonationId: boolean;
|
||||||
public hasPermissionToDeleteAccountBalance: boolean;
|
public hasPermissionToDeleteAccountBalance: boolean;
|
||||||
@ -46,6 +49,9 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
public isLoadingChart: boolean;
|
public isLoadingChart: boolean;
|
||||||
public name: string;
|
public name: string;
|
||||||
public platformName: string;
|
public platformName: string;
|
||||||
|
public sortColumn = 'date';
|
||||||
|
public sortDirection: SortDirection = 'desc';
|
||||||
|
public totalItems: number;
|
||||||
public transactionCount: number;
|
public transactionCount: number;
|
||||||
public user: User;
|
public user: User;
|
||||||
public valueInBaseCurrency: number;
|
public valueInBaseCurrency: number;
|
||||||
@ -77,8 +83,6 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit() {
|
public ngOnInit() {
|
||||||
this.isLoadingActivities = true;
|
|
||||||
|
|
||||||
this.dataService
|
this.dataService
|
||||||
.fetchAccount(this.data.accountId)
|
.fetchAccount(this.data.accountId)
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
@ -110,19 +114,6 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
this.dataService
|
|
||||||
.fetchActivities({
|
|
||||||
filters: [{ id: this.data.accountId, type: 'ACCOUNT' }]
|
|
||||||
})
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe(({ activities }) => {
|
|
||||||
this.activities = activities;
|
|
||||||
|
|
||||||
this.isLoadingActivities = false;
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.impersonationStorageService
|
this.impersonationStorageService
|
||||||
.onChangeHasImpersonation()
|
.onChangeHasImpersonation()
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
@ -131,6 +122,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.fetchAccountBalances();
|
this.fetchAccountBalances();
|
||||||
|
this.fetchActivities();
|
||||||
this.fetchPortfolioPerformance();
|
this.fetchPortfolioPerformance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,12 +143,20 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onExport() {
|
public onExport() {
|
||||||
|
let activityIds = [];
|
||||||
|
|
||||||
|
if (this.user?.settings?.isExperimentalFeatures === true) {
|
||||||
|
activityIds = this.dataSource.data.map(({ id }) => {
|
||||||
|
return id;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
activityIds = this.activities.map(({ id }) => {
|
||||||
|
return id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.dataService
|
this.dataService
|
||||||
.fetchExport(
|
.fetchExport(activityIds)
|
||||||
this.activities.map(({ id }) => {
|
|
||||||
return id;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
.subscribe((data) => {
|
.subscribe((data) => {
|
||||||
downloadAsFile({
|
downloadAsFile({
|
||||||
@ -172,6 +172,13 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onSortChanged({ active, direction }: Sort) {
|
||||||
|
this.sortColumn = active;
|
||||||
|
this.sortDirection = direction;
|
||||||
|
|
||||||
|
this.fetchActivities();
|
||||||
|
}
|
||||||
|
|
||||||
private fetchAccountBalances() {
|
private fetchAccountBalances() {
|
||||||
this.dataService
|
this.dataService
|
||||||
.fetchAccountBalances(this.data.accountId)
|
.fetchAccountBalances(this.data.accountId)
|
||||||
@ -183,6 +190,41 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fetchActivities() {
|
||||||
|
this.isLoadingActivities = true;
|
||||||
|
|
||||||
|
if (this.user?.settings?.isExperimentalFeatures === true) {
|
||||||
|
this.dataService
|
||||||
|
.fetchActivities({
|
||||||
|
filters: [{ id: this.data.accountId, type: 'ACCOUNT' }],
|
||||||
|
sortColumn: this.sortColumn,
|
||||||
|
sortDirection: this.sortDirection
|
||||||
|
})
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe(({ activities, count }) => {
|
||||||
|
this.dataSource = new MatTableDataSource(activities);
|
||||||
|
this.totalItems = count;
|
||||||
|
|
||||||
|
this.isLoadingActivities = false;
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.dataService
|
||||||
|
.fetchActivities({
|
||||||
|
filters: [{ id: this.data.accountId, type: 'ACCOUNT' }]
|
||||||
|
})
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe(({ activities }) => {
|
||||||
|
this.activities = activities;
|
||||||
|
|
||||||
|
this.isLoadingActivities = false;
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fetchPortfolioPerformance() {
|
private fetchPortfolioPerformance() {
|
||||||
this.isLoadingChart = true;
|
this.isLoadingChart = true;
|
||||||
|
|
||||||
|
@ -71,7 +71,25 @@
|
|||||||
>
|
>
|
||||||
<mat-tab>
|
<mat-tab>
|
||||||
<ng-template i18n mat-tab-label>Activities</ng-template>
|
<ng-template i18n mat-tab-label>Activities</ng-template>
|
||||||
|
<gf-activities-table-lazy
|
||||||
|
*ngIf="user?.settings?.isExperimentalFeatures === true"
|
||||||
|
[baseCurrency]="user?.settings?.baseCurrency"
|
||||||
|
[dataSource]="dataSource"
|
||||||
|
[deviceType]="deviceType"
|
||||||
|
[hasPermissionToCreateActivity]="false"
|
||||||
|
[hasPermissionToExportActivities]="!hasImpersonationId && !user.settings.isRestrictedView"
|
||||||
|
[hasPermissionToFilter]="false"
|
||||||
|
[hasPermissionToOpenDetails]="false"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
|
[showActions]="false"
|
||||||
|
[sortColumn]="sortColumn"
|
||||||
|
[sortDirection]="sortDirection"
|
||||||
|
[totalItems]="totalItems"
|
||||||
|
(export)="onExport()"
|
||||||
|
(sortChanged)="onSortChanged($event)"
|
||||||
|
></gf-activities-table-lazy>
|
||||||
<gf-activities-table
|
<gf-activities-table
|
||||||
|
*ngIf="user?.settings?.isExperimentalFeatures !== true"
|
||||||
[activities]="activities"
|
[activities]="activities"
|
||||||
[baseCurrency]="user?.settings?.baseCurrency"
|
[baseCurrency]="user?.settings?.baseCurrency"
|
||||||
[deviceType]="data.deviceType"
|
[deviceType]="data.deviceType"
|
||||||
|
@ -7,6 +7,7 @@ import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-foote
|
|||||||
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
|
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
|
||||||
import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module';
|
import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module';
|
||||||
import { GfAccountBalancesModule } from '@ghostfolio/ui/account-balances/account-balances.module';
|
import { GfAccountBalancesModule } from '@ghostfolio/ui/account-balances/account-balances.module';
|
||||||
|
import { GfActivitiesTableLazyModule } from '@ghostfolio/ui/activities-table-lazy/activities-table-lazy.module';
|
||||||
import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
|
import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
|
||||||
import { GfValueModule } from '@ghostfolio/ui/value';
|
import { GfValueModule } from '@ghostfolio/ui/value';
|
||||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||||
@ -19,6 +20,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
GfAccountBalancesModule,
|
GfAccountBalancesModule,
|
||||||
GfActivitiesTableModule,
|
GfActivitiesTableModule,
|
||||||
|
GfActivitiesTableLazyModule,
|
||||||
GfDialogFooterModule,
|
GfDialogFooterModule,
|
||||||
GfDialogHeaderModule,
|
GfDialogHeaderModule,
|
||||||
GfInvestmentChartModule,
|
GfInvestmentChartModule,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user