From 7d858f86391a3aba3ce48640496923321551a1b3 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 19 Feb 2025 10:32:58 +0100 Subject: [PATCH 1/5] Added summary row to overview --- .../holdings-table.component.html | 35 +++++++++++++++++++ .../holdings-table.component.ts | 13 +++++++ 2 files changed, 48 insertions(+) diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index 5e4526fdc..48a652ebe 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -16,6 +16,7 @@ [tooltip]="element.name" /> + @@ -38,6 +39,7 @@ {{ element.symbol }} + Total @@ -62,6 +64,7 @@ /> + @@ -86,6 +89,14 @@ /> + + + + @@ -107,6 +118,7 @@ /> + @@ -130,6 +142,15 @@ /> + +
+ +
+
@@ -156,6 +177,15 @@ /> + +
+ +
+
@@ -175,6 +205,11 @@ }) " > + diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 14382f420..c40b69a12 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -70,6 +70,10 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { public isLoading = true; public routeQueryParams: Subscription; + protected totalValue = 0; + protected totalChange = 0; + protected totalChangePercentage = 0; + private unsubscribeSubject = new Subject(); public ngOnChanges() { @@ -92,6 +96,15 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { this.dataSource = new MatTableDataSource(this.holdings); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; + this.totalValue = this.dataSource.data.reduce( + (sum, current) => sum + current.valueInBaseCurrency, + 0 + ); + this.totalChange = this.dataSource.data.reduce( + (sum, current) => sum + current.netPerformancePercentWithCurrencyEffect, + 0 + ); + this.totalChangePercentage = (this.totalChange / this.totalValue) * 100; if (this.holdings) { this.isLoading = false; From 5b5b662758b3b322c6b3dedae79cc25d763410ee Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 20 Feb 2025 19:56:15 +0100 Subject: [PATCH 2/5] Add colorSIgn & fix calculation --- libs/ui/src/lib/holdings-table/holdings-table.component.html | 2 ++ libs/ui/src/lib/holdings-table/holdings-table.component.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index 48a652ebe..5067555a1 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -145,6 +145,7 @@
sum + current.valueInBaseCurrency, + (sum, current) => (sum += current.valueInBaseCurrency), 0 ); this.totalChange = this.dataSource.data.reduce( - (sum, current) => sum + current.netPerformancePercentWithCurrencyEffect, + (sum, current) => (sum += current.netPerformanceWithCurrencyEffect), 0 ); this.totalChangePercentage = (this.totalChange / this.totalValue) * 100; From 22aadda15d93b10c84acd1c5fc1eca5d2efafecd Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 20 Feb 2025 20:00:53 +0100 Subject: [PATCH 3/5] Another fix in the calculation --- libs/ui/src/lib/holdings-table/holdings-table.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 57040a96b..b02261377 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -104,7 +104,8 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { (sum, current) => (sum += current.netPerformanceWithCurrencyEffect), 0 ); - this.totalChangePercentage = (this.totalChange / this.totalValue) * 100; + this.totalChangePercentage = + this.totalChange / (this.totalValue - this.totalChange); if (this.holdings) { this.isLoading = false; From 18b2b3518b2b8ead2653a44602c817c53413ea26 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 28 Feb 2025 10:29:11 +0100 Subject: [PATCH 4/5] Fix Holding table footer for smaller devices --- .../src/lib/holdings-table/holdings-table.component.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index 5067555a1..f27a23f11 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -64,7 +64,11 @@ />
- + @@ -90,7 +94,7 @@
- + Date: Sun, 4 May 2025 10:14:00 +0200 Subject: [PATCH 5/5] MR Feedback --- .../src/app/portfolio/portfolio.controller.ts | 10 +++++++++- .../home-holdings/home-holdings.component.ts | 5 ++++- .../home-holdings/home-holdings.html | 1 + .../portfolio-holdings-response.interface.ts | 6 +++++- .../holdings-table.component.html | 14 +++++--------- .../holdings-table/holdings-table.component.ts | 18 ++++++++---------- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 797d0449a..f95499f0b 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -389,6 +389,14 @@ export class PortfolioController { filterByTags }); + const { performance } = await this.portfolioService.getPerformance({ + dateRange, + filters, + impersonationId, + userId: this.request.user.id, + withExcludedAccounts: false + }); + const { holdings } = await this.portfolioService.getDetails({ dateRange, filters, @@ -396,7 +404,7 @@ export class PortfolioController { userId: this.request.user.id }); - return { holdings: Object.values(holdings) }; + return { holdings: Object.values(holdings), performance }; } @Get('investments') diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index dd411f6cc..652e2831e 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -3,6 +3,7 @@ import { ImpersonationStorageService } from '@ghostfolio/client/services/imperso import { UserService } from '@ghostfolio/client/services/user/user.service'; import { AssetProfileIdentifier, + PortfolioPerformance, PortfolioPosition, ToggleOption, User @@ -36,6 +37,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { { label: $localize`Active`, value: 'ACTIVE' }, { label: $localize`Closed`, value: 'CLOSED' } ]; + public performance: PortfolioPerformance; public user: User; public viewModeFormControl = new FormControl( HomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE @@ -162,8 +164,9 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { this.fetchHoldings() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ holdings }) => { + .subscribe(({ holdings, performance }) => { this.holdings = holdings; + this.performance = performance; this.changeDetectorRef.markForCheck(); }); diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index abbc93b3d..5c55845fc 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -51,6 +51,7 @@ [hasPermissionToCreateActivity]="hasPermissionToCreateOrder" [holdings]="holdings" [locale]="user?.settings?.locale" + [performance]="performance" (holdingClicked)="onHoldingClicked($event)" /> @if (hasPermissionToCreateOrder && holdings?.length > 0) { diff --git a/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts b/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts index d2cf38f55..7702bac6c 100644 --- a/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts @@ -1,5 +1,9 @@ -import { PortfolioPosition } from '@ghostfolio/common/interfaces'; +import { + PortfolioPerformance, + PortfolioPosition +} from '@ghostfolio/common/interfaces'; export interface PortfolioHoldingsResponse { holdings: PortfolioPosition[]; + performance: PortfolioPerformance; } diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index f27a23f11..042468429 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -39,7 +39,7 @@ {{ element.symbol }} - Total + Total @@ -95,11 +95,7 @@ - + @@ -153,7 +149,7 @@ [isCurrency]="true" [locale]="locale" [value]="totalChange" - > + /> @@ -189,7 +185,7 @@ [isPercent]="true" [locale]="locale" [value]="totalChangePercentage" - > + /> @@ -214,7 +210,7 @@ diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index b02261377..259567d0c 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -3,6 +3,7 @@ import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { getLocale } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, + PortfolioPerformance, PortfolioPosition } from '@ghostfolio/common/interfaces'; import { GfNoTransactionsInfoComponent } from '@ghostfolio/ui/no-transactions-info'; @@ -58,6 +59,7 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { @Input() holdings: PortfolioPosition[]; @Input() locale = getLocale(); @Input() pageSize = Number.MAX_SAFE_INTEGER; + @Input() performance: PortfolioPerformance; @Output() holdingClicked = new EventEmitter(); @@ -70,9 +72,9 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { public isLoading = true; public routeQueryParams: Subscription; - protected totalValue = 0; protected totalChange = 0; protected totalChangePercentage = 0; + protected totalValue = 0; private unsubscribeSubject = new Subject(); @@ -96,16 +98,12 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { this.dataSource = new MatTableDataSource(this.holdings); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; - this.totalValue = this.dataSource.data.reduce( - (sum, current) => (sum += current.valueInBaseCurrency), - 0 - ); - this.totalChange = this.dataSource.data.reduce( - (sum, current) => (sum += current.netPerformanceWithCurrencyEffect), - 0 - ); + + this.totalChange = + this.performance.netPerformancePercentageWithCurrencyEffect; this.totalChangePercentage = - this.totalChange / (this.totalValue - this.totalChange); + this.performance.netPerformancePercentageWithCurrencyEffect; + this.totalValue = this.performance.currentValueInBaseCurrency; if (this.holdings) { this.isLoading = false;