diff --git a/CHANGELOG.md b/CHANGELOG.md
index 729b4713b..2aa09c05a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- Added a historical cash balances table to the account detail dialog
+
+### Changed
+
- Respected the `withExcludedAccounts` flag in the account balance time series
## 2.27.1 - 2023-11-28
diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
index 284bfcca2..b3a916da9 100644
--- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
+++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
@@ -29,14 +29,15 @@ import { AccountDetailDialogParams } from './interfaces/interfaces';
styleUrls: ['./account-detail-dialog.component.scss']
})
export class AccountDetailDialog implements OnDestroy, OnInit {
+ public activities: OrderWithAccount[];
public balance: number;
public currency: string;
public equity: number;
public hasImpersonationId: boolean;
public historicalDataItems: HistoricalDataItem[];
+ public isLoadingActivities: boolean;
public isLoadingChart: boolean;
public name: string;
- public orders: OrderWithAccount[];
public platformName: string;
public transactionCount: number;
public user: User;
@@ -64,6 +65,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}
public ngOnInit() {
+ this.isLoadingActivities = true;
this.isLoadingChart = true;
this.dataService
@@ -103,7 +105,9 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => {
- this.orders = activities;
+ this.activities = activities;
+
+ this.isLoadingActivities = false;
this.changeDetectorRef.markForCheck();
});
@@ -153,8 +157,8 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
public onExport() {
this.dataService
.fetchExport(
- this.orders.map((order) => {
- return order.id;
+ this.activities.map(({ id }) => {
+ return id;
})
)
.pipe(takeUntil(this.unsubscribeSubject))
diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
index 02d1c917e..7e92eca85 100644
--- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
+++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
@@ -31,7 +31,7 @@
>
-
+
-
-
-
Activities
+
+
+ Activities
-
-
+
+
+ Cash Balances
+
+
+
diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts
index c3d45b6ce..83ac5b6ea 100644
--- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts
+++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts
@@ -2,9 +2,11 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
+import { MatTabsModule } from '@angular/material/tabs';
import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module';
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module';
+import { GfAccountBalancesModule } from '@ghostfolio/ui/account-balances/account-balances.module';
import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
import { GfValueModule } from '@ghostfolio/ui/value';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@@ -15,6 +17,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component';
declarations: [AccountDetailDialog],
imports: [
CommonModule,
+ GfAccountBalancesModule,
GfActivitiesTableModule,
GfDialogFooterModule,
GfDialogHeaderModule,
@@ -22,6 +25,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component';
GfValueModule,
MatButtonModule,
MatDialogModule,
+ MatTabsModule,
NgxSkeletonLoaderModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.html b/apps/client/src/app/pages/portfolio/activities/activities-page.html
index a5c9201a0..8c2cf9bd5 100644
--- a/apps/client/src/app/pages/portfolio/activities/activities-page.html
+++ b/apps/client/src/app/pages/portfolio/activities/activities-page.html
@@ -1,5 +1,5 @@
-
+
Activities
(`/api/v1/account/${aAccountId}`);
}
+ public fetchAccountBalances(aAccountId: string) {
+ return this.http.get(
+ `/api/v1/account/${aAccountId}/balances`
+ );
+ }
+
public fetchAccounts() {
return this.http.get('/api/v1/account');
}
diff --git a/libs/ui/src/lib/account-balances/account-balances.component.html b/libs/ui/src/lib/account-balances/account-balances.component.html
new file mode 100644
index 000000000..81f8a8192
--- /dev/null
+++ b/libs/ui/src/lib/account-balances/account-balances.component.html
@@ -0,0 +1,36 @@
+
+
+
+ Date
+ |
+
+
+ |
+
+
+
+
+ Value
+ |
+
+
+
+
+ |
+
+
+
+
+
diff --git a/libs/ui/src/lib/account-balances/account-balances.component.scss b/libs/ui/src/lib/account-balances/account-balances.component.scss
new file mode 100644
index 000000000..b5b58f67e
--- /dev/null
+++ b/libs/ui/src/lib/account-balances/account-balances.component.scss
@@ -0,0 +1,5 @@
+@import 'apps/client/src/styles/ghostfolio-style';
+
+:host {
+ display: block;
+}
diff --git a/libs/ui/src/lib/account-balances/account-balances.component.ts b/libs/ui/src/lib/account-balances/account-balances.component.ts
new file mode 100644
index 000000000..c552519d6
--- /dev/null
+++ b/libs/ui/src/lib/account-balances/account-balances.component.ts
@@ -0,0 +1,63 @@
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ Input,
+ OnDestroy,
+ OnInit,
+ ViewChild
+} from '@angular/core';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { DataService } from '@ghostfolio/client/services/data.service';
+import { AccountBalancesResponse } from '@ghostfolio/common/interfaces';
+import { get } from 'lodash';
+import { Subject, takeUntil } from 'rxjs';
+
+@Component({
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ selector: 'gf-account-balances',
+ styleUrls: ['./account-balances.component.scss'],
+ templateUrl: './account-balances.component.html'
+})
+export class AccountBalancesComponent implements OnDestroy, OnInit {
+ @Input() accountId: string;
+ @Input() locale: string;
+
+ @ViewChild(MatSort) sort: MatSort;
+
+ public dataSource: MatTableDataSource<
+ AccountBalancesResponse['balances'][0]
+ > = new MatTableDataSource();
+ public displayedColumns: string[] = ['date', 'value'];
+
+ private unsubscribeSubject = new Subject();
+
+ public constructor(
+ private changeDetectorRef: ChangeDetectorRef,
+ private dataService: DataService
+ ) {}
+
+ public ngOnInit() {
+ this.fetchBalances();
+ }
+
+ public ngOnDestroy() {
+ this.unsubscribeSubject.next();
+ this.unsubscribeSubject.complete();
+ }
+
+ private fetchBalances() {
+ this.dataService
+ .fetchAccountBalances(this.accountId)
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe(({ balances }) => {
+ this.dataSource = new MatTableDataSource(balances);
+
+ this.dataSource.sort = this.sort;
+ this.dataSource.sortingDataAccessor = get;
+
+ this.changeDetectorRef.markForCheck();
+ });
+ }
+}
diff --git a/libs/ui/src/lib/account-balances/account-balances.module.ts b/libs/ui/src/lib/account-balances/account-balances.module.ts
new file mode 100644
index 000000000..cc8fb9677
--- /dev/null
+++ b/libs/ui/src/lib/account-balances/account-balances.module.ts
@@ -0,0 +1,15 @@
+import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { MatSortModule } from '@angular/material/sort';
+import { MatTableModule } from '@angular/material/table';
+import { GfValueModule } from '@ghostfolio/ui/value';
+
+import { AccountBalancesComponent } from './account-balances.component';
+
+@NgModule({
+ declarations: [AccountBalancesComponent],
+ exports: [AccountBalancesComponent],
+ imports: [CommonModule, GfValueModule, MatSortModule, MatTableModule],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+})
+export class GfAccountBalancesModule {}