From 9ec4866873ca74876d6b9e2f4dd7a7f3da431013 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:28:37 +0200 Subject: [PATCH 01/86] Bugfix/delete button in activities filter component (#7451) * Fix delete button * Update changelog --- CHANGELOG.md | 1 + .../src/lib/activities-filter/activities-filter.component.html | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5bf323e8..2faf9a643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed the time in market of the portfolio summary to be empty if there is no activity +- Fixed an issue with the delete button in the activities filter component ## 3.35.0 - 2026-07-27 diff --git a/libs/ui/src/lib/activities-filter/activities-filter.component.html b/libs/ui/src/lib/activities-filter/activities-filter.component.html index 58626351b..3243178c9 100644 --- a/libs/ui/src/lib/activities-filter/activities-filter.component.html +++ b/libs/ui/src/lib/activities-filter/activities-filter.component.html @@ -4,12 +4,11 @@ @for (filter of selectedFilters; track filter) { {{ filter.label }} - From e45694f7abb1bfe62810a7265d847f2ad1e1fd3c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:23:17 +0200 Subject: [PATCH 02/86] Task/remove obsolete standalone attribute in page components (#7447) Remove obsolete standalone attribute --- apps/client/src/app/pages/demo/demo-page.component.ts | 1 - apps/client/src/app/pages/i18n/i18n-page.component.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/client/src/app/pages/demo/demo-page.component.ts b/apps/client/src/app/pages/demo/demo-page.component.ts index a4482e36c..871efcd73 100644 --- a/apps/client/src/app/pages/demo/demo-page.component.ts +++ b/apps/client/src/app/pages/demo/demo-page.component.ts @@ -10,7 +10,6 @@ import { Router } from '@angular/router'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'page' }, selector: 'gf-demo-page', - standalone: true, templateUrl: './demo-page.html' }) export class GfDemoPageComponent { diff --git a/apps/client/src/app/pages/i18n/i18n-page.component.ts b/apps/client/src/app/pages/i18n/i18n-page.component.ts index c1f394b00..0cf305bf9 100644 --- a/apps/client/src/app/pages/i18n/i18n-page.component.ts +++ b/apps/client/src/app/pages/i18n/i18n-page.component.ts @@ -4,7 +4,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'page' }, selector: 'gf-i18n-page', - standalone: true, styleUrls: ['./i18n-page.scss'], templateUrl: './i18n-page.html' }) From f1f1f2ca27fe9679cd056917349268f790cbfbfc Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:35:36 +0200 Subject: [PATCH 03/86] Task/improve portfolio summary (#7453) * Improve portfolio summary * Update changelog --- CHANGELOG.md | 1 + .../holding-detail-dialog.html | 2 +- .../portfolio-summary.component.html | 44 +++++++++++++------ .../portfolio-summary.component.ts | 10 +++++ .../analysis/analysis-page.component.ts | 2 +- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2faf9a643..2a812076b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the portfolio summary tab on the home page - Upgraded `@openrouter/ai-sdk-provider` from version `2.9.1` to `3.0.0` - Upgraded `ai` from version `6.0.174` to `7.0.37` diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index 0a8ee6dce..30222de65 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -170,7 +170,7 @@ " [unit]="data.baseCurrency" [value]="investmentInBaseCurrencyWithCurrencyEffect" - >InvestmentInvested Capital @if ( diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index fd0ac9b72..e4ff1ba93 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -57,7 +57,7 @@

-
Investment
+
Invested Capital
- Cash + Holdings @if ( !hasImpersonationId && summary?.totalValueInBaseCurrency > 0 && @@ -175,7 +175,8 @@ class="d-lg-inline-block d-none ml-2 small text-muted" [isPercent]="true" [locale]="locale" - [value]="isLoading ? undefined : cashPercentage" + [precision]="0" + [value]="isLoading ? undefined : holdingsPercentage" /> }
@@ -187,13 +188,13 @@ [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.totalCashInBaseCurrency" + [value]="isLoading ? undefined : holdingsInBaseCurrency" />
- @if (isLoading || summary?.emergencyFund?.cash > 0) { + @if (isLoading || summary?.emergencyFund?.assets > 0) {
-
Buying Power
+
Investments
@@ -216,14 +217,14 @@ [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.emergencyFund?.cash" + [value]="isLoading ? undefined : summary?.emergencyFund?.assets" />
}
- Holdings + Cash @if ( !hasImpersonationId && summary?.totalValueInBaseCurrency > 0 && @@ -233,7 +234,8 @@ class="d-lg-inline-block d-none ml-2 small text-muted" [isPercent]="true" [locale]="locale" - [value]="isLoading ? undefined : holdingsPercentage" + [precision]="0" + [value]="isLoading ? undefined : cashPercentage" /> }
@@ -245,11 +247,25 @@ [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : holdingsInBaseCurrency" + [value]="isLoading ? undefined : summary?.totalCashInBaseCurrency" />
- @if (isLoading || summary?.emergencyFund?.assets > 0) { + @if (isLoading || summary?.emergencyFund?.cash > 0) { +
+
Buying Power
+
+ +
+
Emergency Fund
@@ -260,7 +276,7 @@ [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.emergencyFund?.assets" + [value]="isLoading ? undefined : summary?.emergencyFund?.cash" />
@@ -277,6 +293,7 @@ class="d-lg-inline-block d-none ml-2 small text-muted" [isPercent]="true" [locale]="locale" + [precision]="0" [value]="isLoading ? undefined : excludedFromAnalysisPercentage" /> } @@ -363,6 +380,7 @@ class="d-lg-inline-block d-none ml-2 small text-muted" [isPercent]="true" [locale]="locale" + [precision]="0" [value]="isLoading ? undefined : emergencyFundPercentage" /> } diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts index 1cd2ec93c..eaf71210f 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts @@ -98,6 +98,16 @@ export class GfPortfolioSummaryComponent implements OnChanges { : 0; } + protected get investmentsInBaseCurrency() { + if (!isNumber(this.holdingsInBaseCurrency)) { + return null; + } + + return ( + this.holdingsInBaseCurrency - (this.summary.emergencyFund?.assets ?? 0) + ); + } + public ngOnChanges() { if (this.summary) { if ( diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 990816193..c2d23dbc6 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -82,7 +82,7 @@ export class GfAnalysisPageComponent implements OnInit { protected hasImpersonationId: boolean; protected hasPermissionToReadAiPrompt: boolean; protected investments: InvestmentItem[]; - protected readonly investmentTimelineDataLabel = $localize`Investment`; + protected readonly investmentTimelineDataLabel = $localize`Invested Capital`; protected investmentsByGroup: InvestmentItem[]; protected isLoadingAnalysisPrompt: boolean; protected isLoadingBenchmarkComparator: boolean; From 5e5f67d2112c2d890fbfcd5d6b23dcc978d24f5e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:41:19 +0200 Subject: [PATCH 04/86] Task/extend account deletion email (#7455) Extend account deletion email --- .../user-account-settings.component.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index a62760dad..a556a68d6 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -5,7 +5,10 @@ import { } from '@ghostfolio/client/services/settings-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; -import { E_MAIL_LINE_BREAK } from '@ghostfolio/common/config'; +import { + DEFAULT_LANGUAGE_CODE, + E_MAIL_LINE_BREAK +} from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { downloadAsFile } from '@ghostfolio/common/helper'; import { User } from '@ghostfolio/common/interfaces'; @@ -127,6 +130,14 @@ export class GfUserAccountSettingsComponent implements OnInit { if (state?.user) { this.user = state.user; + const userDetailUrl = [ + window.location.origin, + DEFAULT_LANGUAGE_CODE, + internalRoutes.adminControl.path, + internalRoutes.adminControl.subRoutes.users.path, + this.user.id + ].join('/'); + this.closeUserAccountMailHref = `mailto:hi@ghostfol.io?subject=Delete Account&body=${[ 'Hello', '', @@ -134,7 +145,11 @@ export class GfUserAccountSettingsComponent implements OnInit { '', `User ID: ${this.user.id}`, '', - 'Kind regards' + 'Kind regards', + '', + '', + '---', + userDetailUrl ].join(E_MAIL_LINE_BREAK)}`; this.hasPermissionToDeleteOwnUser = hasPermission( From 81c1e91f0347df3c2d963e999beb3cbc6718a932 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 22:01:09 +0200 Subject: [PATCH 05/86] Task/update locales (#7454) Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.de.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.es.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.fr.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.it.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.ja.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.ko.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.nl.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.pl.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.pt.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.tr.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.uk.xlf | 76 ++++++++++++++----------- apps/client/src/locales/messages.xlf | 74 +++++++++++++----------- apps/client/src/locales/messages.zh.xlf | 76 ++++++++++++++----------- 14 files changed, 614 insertions(+), 448 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 95a13a072..49ddc2157 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -1811,7 +1811,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -2251,7 +2251,7 @@ Poder adquisitiu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -2259,7 +2259,7 @@ Exclòs de l’anàlisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2267,7 +2267,7 @@ Passius apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -2279,7 +2279,7 @@ Valor net apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -2287,7 +2287,7 @@ Rendiment anualitzat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -2295,7 +2295,7 @@ Definiu l’import del vostre fons d’emergència. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2655,7 +2655,7 @@ Automàtic apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2667,7 +2667,7 @@ De debò vols tancar el teu compte de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -2683,7 +2683,7 @@ De debò vols eliminar aquest mètode d’inici de sessió? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2707,7 +2707,7 @@ Ups! Hi ha hagut un error en configurar l’autenticació biomètrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -2850,6 +2850,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication Autenticació biomètrica @@ -3431,7 +3439,7 @@ Com que ja has iniciat sessió, no pots accedir al compte de demostració. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3684,7 +3692,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -4780,7 +4788,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -4802,18 +4810,6 @@ Investment Inversió - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -5997,7 +5993,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -6177,15 +6173,15 @@ Fons d’emergència apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -6445,7 +6441,7 @@ Efectiu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -6620,6 +6616,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Amèrica del Sud @@ -7599,7 +7611,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index ca976d3ae..2932634c5 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -810,7 +810,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -974,7 +974,7 @@ Kaufkraft apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -982,7 +982,7 @@ Gesamtvermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -990,7 +990,7 @@ Performance pro Jahr apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -998,7 +998,7 @@ Bitte setze den Betrag deines Notfallfonds. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -1282,7 +1282,7 @@ Möchtest du diese Anmeldemethode wirklich löschen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -1718,7 +1718,7 @@ Da du bereits eingeloggt bist, kannst du nicht auf die Live Demo zugreifen. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2018,7 +2018,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -2706,7 +2706,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2862,7 +2862,7 @@ Von der Analyse ausgenommen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2870,7 +2870,7 @@ Automatisch apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3050,7 +3050,7 @@ Bargeld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -3166,15 +3166,15 @@ Notfallfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -3285,6 +3285,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Südamerika @@ -3390,7 +3406,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -3649,6 +3665,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Sneak peek at upcoming functionality Vorschau auf kommende Funktionalität @@ -4366,7 +4390,7 @@ Verbindlichkeiten apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -6226,18 +6250,6 @@ Investment Investition - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6617,7 +6629,7 @@ Möchtest du dieses Ghostfolio Konto wirklich schliessen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6689,7 +6701,7 @@ Ups! Beim Einrichten der biometrischen Authentifizierung ist ein Fehler aufgetreten. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7623,7 +7635,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 5ea8880d2..5a402fa83 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -795,7 +795,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -959,7 +959,7 @@ Poder adquisitivo apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -967,7 +967,7 @@ Patrimonio neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -975,7 +975,7 @@ Rendimiento anualizado apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -983,7 +983,7 @@ Por favor, ingresa la cantidad de tu fondo de emergencia. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -1267,7 +1267,7 @@ ¿Seguro que quieres eliminar este método de acceso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -1703,7 +1703,7 @@ Como estás conectado, no puedes acceder a la cuenta de demostración. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2003,7 +2003,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -2683,7 +2683,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2847,7 +2847,7 @@ Excluido del análisis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2855,7 +2855,7 @@ Automático apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3035,7 +3035,7 @@ Efectivo apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -3151,15 +3151,15 @@ Fondo de emergencia apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -3270,6 +3270,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America América del Sur @@ -3367,7 +3383,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -3634,6 +3650,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Sneak peek at upcoming functionality Un adelanto de las próximas funciones @@ -4343,7 +4367,7 @@ Pasivos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -6203,18 +6227,6 @@ Investment Inversión - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6594,7 +6606,7 @@ ¿Seguro que quieres eliminar tu cuenta de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6666,7 +6678,7 @@ ¡Vaya! Hubo un error al configurar la autenticación biométrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7600,7 +7612,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 450a94f26..9cd47942a 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1066,7 +1066,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1278,7 +1278,7 @@ Pouvoir d’Achat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1286,7 +1286,7 @@ Exclus de l’Analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -1294,7 +1294,7 @@ Fortune apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -1302,7 +1302,7 @@ Performance annualisée apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -1310,7 +1310,7 @@ Veuillez entrer le montant de votre fonds d’urgence : apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -1538,7 +1538,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1590,7 +1590,7 @@ Voulez-vous vraiment supprimer cette méthode de connexion ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2038,7 +2038,7 @@ Puisque vous êtes déjà connecté·e, vous ne pouvez pas accéder au compte de démonstration. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2110,7 +2110,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -2602,7 +2602,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -3066,7 +3066,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -3206,15 +3206,15 @@ Fonds d’Urgence apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -3286,7 +3286,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -3453,6 +3453,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Amérique du Sud @@ -3633,6 +3649,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Sneak peek at upcoming functionality Avant-première de fonctionnalités futures @@ -4342,7 +4366,7 @@ Dettes apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -6202,18 +6226,6 @@ Investment Investissement - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6593,7 +6605,7 @@ Confirmer la suppresion de votre compte Ghostfolio ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6665,7 +6677,7 @@ Oops! Une erreur s’est produite lors de la configuration de l’authentification biométrique. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7599,7 +7611,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 49026ae6a..9e4687a8b 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -795,7 +795,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -959,7 +959,7 @@ Potere d’acquisto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -967,7 +967,7 @@ Patrimonio netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -975,7 +975,7 @@ Prestazioni annualizzate apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -983,7 +983,7 @@ Inserisci l’importo del tuo fondo di emergenza: apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -1267,7 +1267,7 @@ Vuoi davvero rimuovere questo metodo di accesso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -1703,7 +1703,7 @@ Poiché hai già effettuato l’accesso, non puoi accedere all’account demo. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2003,7 +2003,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -2683,7 +2683,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2847,7 +2847,7 @@ Escluso dall’analisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2855,7 +2855,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3035,7 +3035,7 @@ Contanti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -3151,15 +3151,15 @@ Fondo di emergenza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -3270,6 +3270,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Sud America @@ -3367,7 +3383,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -3634,6 +3650,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Sneak peek at upcoming functionality Un’anteprima delle funzionalità in arrivo @@ -4343,7 +4367,7 @@ Passività apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -6203,18 +6227,6 @@ Investment Investimento - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6594,7 +6606,7 @@ Confermi di voler chiudere il tuo account Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6666,7 +6678,7 @@ Ops! C’è stato un errore impostando l’autenticazione biometrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7600,7 +7612,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.ja.xlf b/apps/client/src/locales/messages.ja.xlf index 656891a9e..1ccffa825 100644 --- a/apps/client/src/locales/messages.ja.xlf +++ b/apps/client/src/locales/messages.ja.xlf @@ -1660,7 +1660,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1984,7 +1984,7 @@ 購買力 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1992,7 +1992,7 @@ 分析から除外 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2000,7 +2000,7 @@ 負債 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -2012,7 +2012,7 @@ 純資産(ネットワース) apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -2020,7 +2020,7 @@ 年率換算パフォーマンス apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -2028,7 +2028,7 @@ 緊急用資金の金額を設定してください。 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2428,7 +2428,7 @@ オート apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2440,7 +2440,7 @@ このサインイン方法を本当に削除しますか? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2575,6 +2575,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication 生体認証 @@ -3120,7 +3128,7 @@ すでにログインしているため、デモアカウントにアクセスできません。 apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3348,7 +3356,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -4428,7 +4436,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -5453,7 +5461,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -5625,15 +5633,15 @@ 緊急資金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -5885,7 +5893,7 @@ 現金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -6052,6 +6060,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America 南米 @@ -6251,18 +6275,6 @@ Investment 投資 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6626,7 +6638,7 @@ Ghostfolioアカウントを本当に閉鎖しますか? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6690,7 +6702,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7624,7 +7636,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.ko.xlf b/apps/client/src/locales/messages.ko.xlf index 00cb62538..ebda4cbf4 100644 --- a/apps/client/src/locales/messages.ko.xlf +++ b/apps/client/src/locales/messages.ko.xlf @@ -1660,7 +1660,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1984,7 +1984,7 @@ 매수 가능 금액 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1992,7 +1992,7 @@ 분석에서 제외됨 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2000,7 +2000,7 @@ 부채 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -2012,7 +2012,7 @@ 순자산 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -2020,7 +2020,7 @@ 연환산 성과 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -2028,7 +2028,7 @@ 비상금 금액을 설정해 주세요. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2428,7 +2428,7 @@ 자동 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2440,7 +2440,7 @@ 이 로그인 방법을 정말로 제거하시겠습니까? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2575,6 +2575,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication 생체인증 @@ -3120,7 +3128,7 @@ 이미 로그인되어 있으므로 데모 계정에 접근할 수 없습니다. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3348,7 +3356,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -4420,7 +4428,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -5445,7 +5453,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -5617,15 +5625,15 @@ 비상자금 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -5885,7 +5893,7 @@ 현금 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -6052,6 +6060,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America 남아메리카 @@ -6251,18 +6275,6 @@ Investment 투자 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6626,7 +6638,7 @@ 정말로 Ghostfolio 계정을 폐쇄하시겠습니까? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6690,7 +6702,7 @@ 이런! 생체 인증을 설정하는 중에 오류가 발생했습니다. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7624,7 +7636,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 39e8e4931..85c025f80 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -794,7 +794,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -958,7 +958,7 @@ Koopkracht apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -966,7 +966,7 @@ Netto waarde apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -974,7 +974,7 @@ Rendement per jaar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -982,7 +982,7 @@ Voer het bedrag van je noodfonds in: apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -1266,7 +1266,7 @@ Wil je deze aanmeldingsmethode echt verwijderen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -1702,7 +1702,7 @@ Aangezien je al ingelogd bent, heb je geen toegang tot de demo-account. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2002,7 +2002,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -2682,7 +2682,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2846,7 +2846,7 @@ Uitgesloten van analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2854,7 +2854,7 @@ Automatisch apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3034,7 +3034,7 @@ Contant geld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -3150,15 +3150,15 @@ Noodfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -3269,6 +3269,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Zuid-Amerika @@ -3366,7 +3382,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -3633,6 +3649,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Sneak peek at upcoming functionality Voorproefje van nieuwe functionaliteit @@ -4342,7 +4366,7 @@ Verplichtingen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -6202,18 +6226,6 @@ Investment Investering - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6593,7 +6605,7 @@ Wilt u uw Ghostfolio account echt sluiten? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6665,7 +6677,7 @@ Oeps! Er is een fout opgetreden met het instellen van de biometrische authenticatie. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7599,7 +7611,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 1aac9ae83..83a3a78b3 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -1627,7 +1627,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1951,7 +1951,7 @@ Siła Nabywcza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1959,7 +1959,7 @@ Wykluczone z Analizy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -1967,7 +1967,7 @@ Pasywa (Zobowiązania Finansowe) apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -1979,7 +1979,7 @@ Wartość Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -1987,7 +1987,7 @@ Osiągi w Ujęciu Rocznym apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -1995,7 +1995,7 @@ Wprowadź wysokość funduszu rezerwowego: apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2395,7 +2395,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2407,7 +2407,7 @@ Czy na pewno chcesz usunąć tą metode logowania? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2542,6 +2542,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication Uwierzytelnianie Biometryczne @@ -3087,7 +3095,7 @@ Ponieważ jesteś już zalogowany, nie możesz uzyskać dostępu do konta demo. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3315,7 +3323,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -4387,7 +4395,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -5368,7 +5376,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -5540,15 +5548,15 @@ Fundusz Rezerwowy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -5808,7 +5816,7 @@ Gotówka apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -5975,6 +5983,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Ameryka Południowa @@ -6202,18 +6226,6 @@ Investment Inwestycje - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6593,7 +6605,7 @@ Czy na pewno chcesz zamknąć swoje konto Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6665,7 +6677,7 @@ Ups! Wystąpił błąd podczas konfigurowania uwierzytelniania biometrycznego. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7599,7 +7611,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 74434fb9f..9ab235194 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -910,7 +910,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1130,7 +1130,7 @@ Poder de Compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1138,7 +1138,7 @@ Excluído da Análise apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -1146,7 +1146,7 @@ Valor Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -1154,7 +1154,7 @@ Desempenho Anual apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -1162,7 +1162,7 @@ Por favor, insira o valor do seu fundo de emergência: apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -1518,7 +1518,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1570,7 +1570,7 @@ Deseja realmente remover este método de início de sessão? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2006,7 +2006,7 @@ Como já tem sessão iniciada, não pode aceder à conta de demonstração. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2602,7 +2602,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -2958,7 +2958,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -3034,15 +3034,15 @@ Fundo de Emergência apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -3114,7 +3114,7 @@ Dinheiro apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -3281,6 +3281,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America América do Sul @@ -3442,7 +3458,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -3633,6 +3649,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Sneak peek at upcoming functionality Acesso antecipado a funcionalidades futuras @@ -4342,7 +4366,7 @@ Responsabilidades apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -6202,18 +6226,6 @@ Investment Investimento - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6593,7 +6605,7 @@ Você realmente deseja encerrar sua conta Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6665,7 +6677,7 @@ Ops! Ocorreu um erro ao configurar a autenticação biométrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7599,7 +7611,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index dedde6a2e..1415f480d 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -1475,7 +1475,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1787,7 +1787,7 @@ Alım Limiti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1795,7 +1795,7 @@ Analize Dahil Edilmemiştir. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -1803,7 +1803,7 @@ Yükümlülükler apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -1815,7 +1815,7 @@ Toplam Varlık apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -1823,7 +1823,7 @@ Yıllıklandırılmış Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -1831,7 +1831,7 @@ Lütfen acil durum yedeği meblağını giriniz: apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2591,7 +2591,7 @@ Oturum açmış olduğunuz için demo hesabına erişemezsiniz. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -2831,7 +2831,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -3803,7 +3803,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -4608,7 +4608,7 @@ Otomatik apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -4660,7 +4660,7 @@ Bu giriş yöntemini kaldırmayı gerçekten istiyor musunuz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -4823,6 +4823,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication Biyometrik Kimlik Doğrulama @@ -5056,7 +5064,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -5228,15 +5236,15 @@ Acil Durum Fonu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -5480,7 +5488,7 @@ Nakit apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -5647,6 +5655,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Güney Amerika @@ -6202,18 +6226,6 @@ Investment Yatırım - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6593,7 +6605,7 @@ Ghostfolio hesabınızı kapatmak istediğinize emin misiniz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6665,7 +6677,7 @@ Oops! Biyometrik kimlik doğrulama ayarlanırken bir hata oluştu. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7599,7 +7611,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index a4ef1f24e..d0017b1b4 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -1927,7 +1927,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -2351,7 +2351,7 @@ Купівельна спроможність apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -2359,7 +2359,7 @@ Виключено з аналізу apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -2367,7 +2367,7 @@ Зобов’язання apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -2379,7 +2379,7 @@ Чиста вартість apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -2387,7 +2387,7 @@ Річна доходність apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -2415,7 +2415,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html @@ -2443,7 +2443,7 @@ Будь ласка, встановіть суму вашого резервного фонду. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2955,7 +2955,7 @@ Автоматичний apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2967,7 +2967,7 @@ Ви дійсно хочете закрити ваш обліковий запис Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -2983,7 +2983,7 @@ Ви дійсно хочете вилучити цей спосіб входу? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -3007,7 +3007,7 @@ Упс! Виникла помилка під час налаштування біометричної автентифікації. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -3150,6 +3150,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication Біометрична аутентифікація @@ -3727,7 +3735,7 @@ Оскільки ви вже ввійшли, ви не можете отримати доступ до демонстраційного обліковий запис. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3980,7 +3988,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -5120,7 +5128,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -5142,18 +5150,6 @@ Investment Інвестиції - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6787,7 +6783,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -7099,15 +7095,15 @@ Резервний фонд apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -7391,7 +7387,7 @@ Готівка apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -7566,6 +7562,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America Південна Америка diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index c91f285a1..4cfa2ab2f 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -1523,7 +1523,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1816,21 +1816,21 @@ Buying Power apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 Excluded from Analysis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 Liabilities apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -1841,21 +1841,21 @@ Net Worth apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 Annualized Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 Please set the amount of your emergency fund. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2220,7 +2220,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2231,7 +2231,7 @@ Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2351,6 +2351,13 @@ 221 + + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication @@ -2860,7 +2867,7 @@ As you are already logged in, you cannot access the demo account. apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3067,7 +3074,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -4036,7 +4043,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -4958,7 +4965,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -5119,15 +5126,15 @@ Emergency Fund apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -5355,7 +5362,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -5503,6 +5510,21 @@ 79 + + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America @@ -5681,18 +5703,6 @@ Investment - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6017,7 +6027,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6073,7 +6083,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -6920,7 +6930,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 06cc8c09e..ed360263d 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -1636,7 +1636,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 215 + 230 @@ -1960,7 +1960,7 @@ 购买力 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 196 + 256 @@ -1968,7 +1968,7 @@ 从分析中排除 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 270 + 286 @@ -1976,7 +1976,7 @@ 负债 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 298 + 315 apps/client/src/app/pages/features/features-page.html @@ -1988,7 +1988,7 @@ 净值 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 320 + 337 @@ -1996,7 +1996,7 @@ 年化业绩 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 334 + 351 @@ -2004,7 +2004,7 @@ 请输入您的应急基金金额。 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 135 + 145 @@ -2404,7 +2404,7 @@ 自动 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 74 + 77 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2416,7 +2416,7 @@ 您确实要删除此登录方法吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 318 @@ -2551,6 +2551,14 @@ 221 + + Investments + Investments + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 197 + + Biometric Authentication 生物识别认证 @@ -3096,7 +3104,7 @@ 由于您已经登录,因此无法访问模拟帐户。 apps/client/src/app/pages/demo/demo-page.component.ts - 33 + 32 @@ -3324,7 +3332,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 168 apps/client/src/app/pages/public/public-page.html @@ -4404,7 +4412,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 419 + 437 apps/client/src/app/pages/features/features-page.html @@ -5429,7 +5437,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 406 + 424 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -5601,15 +5609,15 @@ 应急基金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 254 + 270 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 356 + 373 apps/client/src/app/pages/features/features-page.html @@ -5861,7 +5869,7 @@ 现金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 168 + 227 libs/ui/src/lib/i18n.ts @@ -6028,6 +6036,22 @@ 79 + + Invested Capital + Invested Capital + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 173 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 85 + + South America 南美洲 @@ -6227,18 +6251,6 @@ Investment 投资 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 - - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 60 - - - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 85 - apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 101 @@ -6594,7 +6606,7 @@ 您确定要关闭您的 Ghostfolio 账户吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 229 + 244 @@ -6666,7 +6678,7 @@ 哎呀!设置生物识别认证时发生错误。 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 352 + 367 @@ -7600,7 +7612,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts - 133 + 143 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html From 65c2575bd76fcdc11d427f89a1c2a345bb49ed12 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 07:58:16 +0200 Subject: [PATCH 06/86] Task/improve language localization for DE (20260729) (#7457) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.de.xlf | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a812076b..0ebb7b175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the portfolio summary tab on the home page +- Improved the language localization for German (`de`) - Upgraded `@openrouter/ai-sdk-provider` from version `2.9.1` to `3.0.0` - Upgraded `ai` from version `6.0.174` to `7.0.37` diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 2932634c5..9bcc596fd 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -3287,7 +3287,7 @@ Invested Capital - Invested Capital + Investiertes Kapital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 173 @@ -3667,7 +3667,7 @@ Investments - Investments + Investitionen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 197 From f336247e8bec477cc8a48666e52f50ab4cba5ee2 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:17:39 +0200 Subject: [PATCH 07/86] Task/add overview tab to account detail dialog (#7462) * Add overview tab * Update changelog --- CHANGELOG.md | 4 + .../account-detail-dialog.component.ts | 13 +- .../account-detail-dialog.html | 141 ++++++++++-------- 3 files changed, 92 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ebb7b175..6ea3a228e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added an overview tab to the account detail dialog + ### Changed - Improved the portfolio summary tab on the home page 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 62b87cfc0..53365c543 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 @@ -48,6 +48,7 @@ import { addIcons } from 'ionicons'; import { albumsOutline, cashOutline, + readerOutline, swapVerticalOutline } from 'ionicons/icons'; import { isNumber } from 'lodash'; @@ -97,7 +98,6 @@ export class GfAccountDetailDialogComponent implements OnInit { protected holdings: PortfolioPosition[]; protected interestInBaseCurrency: number; protected interestInBaseCurrencyPrecision = 2; - protected isLoadingActivities: boolean; protected isLoadingChart: boolean; protected name: string | null; protected pageIndex = 0; @@ -148,7 +148,12 @@ export class GfAccountDetailDialogComponent implements OnInit { } }); - addIcons({ albumsOutline, cashOutline, swapVerticalOutline }); + addIcons({ + albumsOutline, + cashOutline, + readerOutline, + swapVerticalOutline + }); } public ngOnInit() { @@ -288,8 +293,6 @@ export class GfAccountDetailDialogComponent implements OnInit { } private fetchActivities() { - this.isLoadingActivities = true; - this.dataService .fetchActivities({ filters: [{ id: this.data.accountId, type: 'ACCOUNT' }], @@ -303,8 +306,6 @@ export class GfAccountDetailDialogComponent implements OnInit { this.dataSource = new MatTableDataSource(activities); this.totalItems = count; - this.isLoadingActivities = false; - this.changeDetectorRef.markForCheck(); }); } 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 5c5be6cb7..6fca90718 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 @@ -30,70 +30,91 @@ /> -
-
- Cash Balance -
-
- Equity -
-
- Interest -
-
- Dividend -
-
- Activities -
-
- Platform -
-
- + + + +
Overview
+
+
+
+
+ Cash Balance +
+
+ Equity +
+
+ Interest +
+
+ Dividend +
+
+ + @if (activitiesCount === 1) { + Activity + } @else { + Activities + } + +
+
+ Platform +
+
+
+
From 7635bea1384d89158bf0e04a4e79f04b1f912ade Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:21:00 +0200 Subject: [PATCH 08/86] Bugfix/fix tags in readonly mode of tags selector component (#7461) * Fix tags in read-only mode * Update changelog --- CHANGELOG.md | 1 + .../lib/tags-selector/tags-selector.component.html | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea3a228e..59123bd50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed the time in market of the portfolio summary to be empty if there is no activity - Fixed an issue with the delete button in the activities filter component +- Fixed the tags in the read-only mode of the tags selector component ## 3.35.0 - 2026-07-27 diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.html b/libs/ui/src/lib/tags-selector/tags-selector.component.html index 4f9d82ae9..bd56e9318 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.html +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -3,22 +3,20 @@ @if (readonly) {
Tags
@if ( - (tags && tags.length > 0) || (tagsReadOnly && tagsReadOnly.length > 0) + tagsSelected().length > 0 || (tagsReadOnly && tagsReadOnly.length > 0) ) { @if (tagsReadOnly) { - @for (tag of tagsReadOnly; track tag) { + @for (tag of tagsReadOnly; track tag.id) { {{ tag.name }} } } - @if (tags) { - @for (tag of tags; track tag) { - {{ tag.name }} - } + @for (tag of tagsSelected(); track tag.id) { + {{ tag.name }} } } @else { -
-
+
} } @else { From 19fe44765553940516a4c65f9ea918707989bc06 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:31:38 +0200 Subject: [PATCH 09/86] Feature/add tags to account detail dialog (#7460) * Add tags (read-only) * Update changelog --- CHANGELOG.md | 1 + .../account-detail-dialog.component.ts | 15 +++++++++++++++ .../account-detail-dialog.html | 4 ++++ .../lib/tags-selector/tags-selector.component.ts | 2 +- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59123bd50..dfa80447b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added an overview tab to the account detail dialog +- Added the tags (read-only) to the account detail dialog (experimental) ### Changed 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 53365c543..fdb0ba97a 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 @@ -20,7 +20,9 @@ import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfDialogFooterComponent } from '@ghostfolio/ui/dialog-footer'; import { GfDialogHeaderComponent } from '@ghostfolio/ui/dialog-header'; import { GfHoldingsTableComponent } from '@ghostfolio/ui/holdings-table'; +import { translate } from '@ghostfolio/ui/i18n'; import { DataService } from '@ghostfolio/ui/services'; +import { GfTagsSelectorComponent } from '@ghostfolio/ui/tags-selector'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { @@ -42,6 +44,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { NavigationStart, Router } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; +import { Tag } from '@prisma/client'; import { Big } from 'big.js'; import { format, parseISO } from 'date-fns'; import { addIcons } from 'ionicons'; @@ -70,6 +73,7 @@ import { GfDialogHeaderComponent, GfHoldingsTableComponent, GfInvestmentChartComponent, + GfTagsSelectorComponent, GfValueComponent, IonIcon, MatButtonModule, @@ -105,6 +109,7 @@ export class GfAccountDetailDialogComponent implements OnInit { protected platformName: string; protected sortColumn = 'date'; protected sortDirection: SortDirection = 'desc'; + protected tags: Tag[]; protected totalItems: number; protected user: User; protected valueInBaseCurrency: number; @@ -236,6 +241,7 @@ export class GfAccountDetailDialogComponent implements OnInit { interestInBaseCurrency, name, platform, + tags, value, valueInBaseCurrency }) => { @@ -285,6 +291,15 @@ export class GfAccountDetailDialogComponent implements OnInit { this.name = name; this.platformName = platform?.name ?? '-'; + + this.tags = + tags?.map((tag) => { + return { + ...tag, + name: translate(tag.name) + }; + }) ?? []; + this.valueInBaseCurrency = valueInBaseCurrency; this.changeDetectorRef.markForCheck(); 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 6fca90718..b7deae6e8 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 @@ -179,6 +179,10 @@ />
+ + @if (user?.settings?.isExperimentalFeatures) { + + } diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.ts index c0d5fe6a6..0e97e12fd 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.ts @@ -167,7 +167,7 @@ export class GfTagsSelectorComponent return id; }); - return this.tagsAvailable + return (this.tagsAvailable ?? []) .filter(({ id, name }) => { return ( !tagIds.includes(id) && From 79c73315f71fb98ec7443df968da7c484b1de8a6 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:27:02 +0200 Subject: [PATCH 10/86] Release 3.36.0 (#7464) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfa80447b..335743775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 3.36.0 - 2026-07-29 ### Added diff --git a/package-lock.json b/package-lock.json index d2837bde1..2f55459e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.35.0", + "version": "3.36.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.35.0", + "version": "3.36.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index ccca3f2b1..40b2ef182 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.35.0", + "version": "3.36.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 17f0fe87b19c2a4de2ce871d1ffd1578fe971eab Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 17:49:11 +0200 Subject: [PATCH 11/86] Task/move tags to overview tab of account and holding detail dialogs (#7465) * Move tags to overview tab * Update changelog --- CHANGELOG.md | 7 +++++++ .../account-detail-dialog.html | 9 ++++---- .../holding-detail-dialog.html | 21 ++++++++++--------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 335743775..2b33b1405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Moved the tags to the overview tab of the account detail dialog (experimental) +- Moved the tags to the overview tab of the holding detail dialog + ## 3.36.0 - 2026-07-29 ### Added 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 b7deae6e8..32a11717f 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 @@ -112,6 +112,11 @@ >Platform + @if (user?.settings?.isExperimentalFeatures) { +
+ +
+ } @@ -179,10 +184,6 @@ /> - - @if (user?.settings?.isExperimentalFeatures) { - - } diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index 30222de65..464f0b6b2 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -331,6 +331,17 @@ >ISIN +
+
+ + +
@if (dataProviderInfo) {
@@ -419,16 +430,6 @@ } -
- - - @if ( data.hasPermissionToAccessAdminControl || (dataSource?.data.length > 0 && From b8f6037f8c0612bf719ad1a3c7d84312407f57b1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:04:12 +0200 Subject: [PATCH 12/86] Bugfix/ignore future-dated account balances in portfolio calculation (#7436) * Ignore future-dated account balances in the portfolio calculation * Update changelog --- CHANGELOG.md | 4 +++ .../account-balance.service.ts | 12 +++++-- apps/api/src/app/account/account.service.ts | 32 ++++++++++++++++--- .../src/app/activities/activities.service.ts | 15 ++++++++- .../roai/portfolio-calculator-cash.spec.ts | 8 +++++ apps/api/src/helper/account.helper.ts | 17 ++++++++++ 6 files changed, 80 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b33b1405..f78b9dad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved the tags to the overview tab of the account detail dialog (experimental) - Moved the tags to the overview tab of the holding detail dialog +### Fixed + +- Ignored future-dated account balances in the portfolio calculation + ## 3.36.0 - 2026-07-29 ### Added diff --git a/apps/api/src/app/account-balance/account-balance.service.ts b/apps/api/src/app/account-balance/account-balance.service.ts index 84932f429..29c7f2887 100644 --- a/apps/api/src/app/account-balance/account-balance.service.ts +++ b/apps/api/src/app/account-balance/account-balance.service.ts @@ -1,5 +1,8 @@ import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; -import { WHERE_ACCOUNT_NOT_EXCLUDED } from '@ghostfolio/api/helper/account.helper'; +import { + isAccountBalanceInFuture, + WHERE_ACCOUNT_NOT_EXCLUDED +} from '@ghostfolio/api/helper/account.helper'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; @@ -15,7 +18,7 @@ import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { AccountBalance, Prisma } from '@prisma/client'; import { Big } from 'big.js'; -import { format, parseISO } from 'date-fns'; +import { endOfToday, format, parseISO } from 'date-fns'; import { groupBy } from 'lodash'; @Injectable() @@ -114,8 +117,13 @@ export class AccountBalanceService { const accumulatedBalancesByDate: { [date: string]: HistoricalDataItem } = {}; const lastBalancesByAccount: { [accountId: string]: Big } = {}; + const endOfTodayDate = endOfToday(); for (const { accountId, date, valueInBaseCurrency } of balances) { + if (isAccountBalanceInFuture({ date, endOfTodayDate })) { + continue; + } + const formattedDate = format(date, DATE_FORMAT); lastBalancesByAccount[accountId] = new Big(valueInBaseCurrency); diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 209806234..7f0451101 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -1,6 +1,10 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; -import { WHERE_ACCOUNT_NOT_EXCLUDED } from '@ghostfolio/api/helper/account.helper'; +import { + getWhereAccountBalanceNotInFuture, + isAccountBalanceInFuture, + WHERE_ACCOUNT_NOT_EXCLUDED +} from '@ghostfolio/api/helper/account.helper'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; @@ -19,7 +23,7 @@ import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { format } from 'date-fns'; +import { endOfToday, format } from 'date-fns'; import { groupBy } from 'lodash'; import { CashDetails } from './interfaces/cash-details.interface'; @@ -41,7 +45,9 @@ export class AccountService { include: { balances: { orderBy: { date: 'desc' }, - take: 1 + take: 1, + // Ignore account balances in the future + where: getWhereAccountBalanceNotInFuture() } }, where: { id_userId } @@ -95,7 +101,16 @@ export class AccountService { include.balances = { orderBy: { date: 'desc' }, - ...(isBalancesIncluded ? {} : { take: 1 }) + // If the balances are included, they are returned as-is (including the + // ones in the future) because the client renders the full history. The + // balance is derived below and skips the account balances in the future. + ...(isBalancesIncluded + ? {} + : { + take: 1, + // Ignore account balances in the future + where: getWhereAccountBalanceNotInFuture() + }) }; if (isTagsIncluded) { @@ -115,10 +130,17 @@ export class AccountService { where }); + const endOfTodayDate = endOfToday(); + return accounts.map((account) => { const result = { ...account, - balance: account.balances[0]?.value ?? 0, + balance: + // The balances are ordered by date descending, hence the first account + // balance which is not in the future reflects the current balance + account.balances.find(({ date }) => { + return !isAccountBalanceInFuture({ date, endOfTodayDate }); + })?.value ?? 0, tags: isTagsIncluded ? (account.tags as unknown as { tag: Tag }[]).map(({ tag }) => { return tag; diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index 0a390d4ec..7d6e822c5 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -3,7 +3,10 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; import { AssetProfileChangedEvent } from '@ghostfolio/api/events/asset-profile-changed.event'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; -import { WHERE_ACCOUNT_NOT_EXCLUDED } from '@ghostfolio/api/helper/account.helper'; +import { + isAccountBalanceInFuture, + WHERE_ACCOUNT_NOT_EXCLUDED +} from '@ghostfolio/api/helper/account.helper'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; @@ -456,6 +459,7 @@ export class ActivitiesService { } const activities: Activity[] = []; + const endOfTodayDate = endOfToday(); for (const account of cashDetails.accounts) { const { balances } = await this.accountBalanceService.getAccountBalances({ @@ -468,6 +472,15 @@ export class ActivitiesService { let currentBalanceInBaseCurrency = 0; for (const balanceItem of balances) { + if ( + isAccountBalanceInFuture({ + endOfTodayDate, + date: balanceItem.date + }) + ) { + continue; + } + const syntheticActivityTemplate: Activity = { userId, accountId: account.id, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index 9bef6ad39..1fc705b46 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -166,6 +166,14 @@ describe('PortfolioCalculator', () => { id: randomUUID(), value: 2000, valueInBaseCurrency: 1800 + }, + { + // Ignored future account balance + accountId, + date: parseDate('2050-12-31'), + id: randomUUID(), + value: 0, + valueInBaseCurrency: 0 } ] }); diff --git a/apps/api/src/helper/account.helper.ts b/apps/api/src/helper/account.helper.ts index 0800c022e..8e7520d0a 100644 --- a/apps/api/src/helper/account.helper.ts +++ b/apps/api/src/helper/account.helper.ts @@ -1,6 +1,7 @@ import { TAG_ID_EXCLUDE_FROM_ANALYSIS } from '@ghostfolio/common/config'; import { Prisma } from '@prisma/client'; +import { endOfToday, isAfter } from 'date-fns'; export const WHERE_ACCOUNT_NOT_EXCLUDED: Prisma.AccountWhereInput = { isExcluded: false, @@ -10,3 +11,19 @@ export const WHERE_ACCOUNT_NOT_EXCLUDED: Prisma.AccountWhereInput = { } } }; + +export function getWhereAccountBalanceNotInFuture(): Prisma.AccountBalanceWhereInput { + return { + date: { lte: endOfToday() } + }; +} + +export function isAccountBalanceInFuture({ + date, + endOfTodayDate = endOfToday() +}: { + date: Date; + endOfTodayDate?: Date; +}) { + return isAfter(date, endOfTodayDate); +} From 6318c064af4f6f05f4a39c27016c67c175daf6e4 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:16:48 +0200 Subject: [PATCH 13/86] Task/refactor line charts to share chart configuration (#7438) * Refactor line chart components to share common chart configuration * Update changelog --- CHANGELOG.md | 1 + .../benchmark-comparator.component.ts | 109 +++++------------ .../investment-chart.component.ts | 111 +++++------------- libs/common/src/lib/chart-helper.ts | 110 ++++++++++++++++- libs/ui/src/lib/chart/chart.options.ts | 28 +++++ libs/ui/src/lib/chart/index.ts | 1 + .../lib/line-chart/line-chart.component.ts | 91 +++++--------- 7 files changed, 225 insertions(+), 226 deletions(-) create mode 100644 libs/ui/src/lib/chart/chart.options.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f78b9dad5..fcad150f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved the tags to the overview tab of the account detail dialog (experimental) - Moved the tags to the overview tab of the holding detail dialog +- Refactored the line chart components to share the common chart configuration ### Fixed diff --git a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts index c474e29ab..0091ae5d7 100644 --- a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts +++ b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1,20 +1,21 @@ import { - getTooltipOptions, - getVerticalHoverLinePlugin + getChartBorderColor, + getChartElementsOptions, + getTimeAxisOptions, + getValueAxisOptions, + getVerticalHoverLinePlugin, + getZeroLineAnnotation } from '@ghostfolio/common/chart-helper'; import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; -import { - getBackgroundColor, - getDateFormatString, - getLocale, - getTextColor, - parseDate -} from '@ghostfolio/common/helper'; +import { getLocale, parseDate } from '@ghostfolio/common/helper'; import { LineChartItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { ColorScheme } from '@ghostfolio/common/types'; -import { registerChartConfiguration } from '@ghostfolio/ui/chart'; +import { + getTimeSeriesTooltipOptions, + registerChartConfiguration +} from '@ghostfolio/ui/chart'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { @@ -166,28 +167,13 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { data, options: { animation: false, - elements: { - line: { - tension: 0 - }, - point: { - hoverBackgroundColor: getBackgroundColor(this.colorScheme()), - hoverRadius: 2, - radius: 0 - } - }, + elements: getChartElementsOptions(this.colorScheme()), interaction: { intersect: false, mode: 'index' }, maintainAspectRatio: true, plugins: { annotation: { annotations: { - yAxis: { - borderColor: `rgba(${getTextColor(this.colorScheme())}, 0.1)`, - borderWidth: 1, - scaleID: 'y', - type: 'line', - value: 0 - } + yAxis: getZeroLineAnnotation(this.colorScheme()) } }, legend: { @@ -195,54 +181,21 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { }, tooltip: this.getTooltipPluginConfiguration(), verticalHoverLine: { - color: `rgba(${getTextColor(this.colorScheme())}, 0.1)` + color: getChartBorderColor(this.colorScheme()) } }, responsive: true, scales: { - x: { - border: { - color: `rgba(${getTextColor(this.colorScheme())}, 0.1)`, - width: 1 - }, - display: true, - grid: { - display: false - }, - type: 'time', - time: { - tooltipFormat: getDateFormatString(this.locale()), - unit: 'year' + x: getTimeAxisOptions({ + colorScheme: this.colorScheme(), + locale: this.locale() + }), + y: getValueAxisOptions({ + colorScheme: this.colorScheme(), + tickCallback: (tickValue) => { + return `${Number(tickValue).toFixed(2)} %`; } - }, - y: { - border: { - width: 0 - }, - display: true, - grid: { - color: ({ scale, tick }) => { - if ( - tick.value === 0 || - tick.value === scale.max || - tick.value === scale.min - ) { - return `rgba(${getTextColor(this.colorScheme())}, 0.1)`; - } - - return 'transparent'; - } - }, - position: 'right', - ticks: { - callback: (value: number) => { - return `${value.toFixed(2)} %`; - }, - display: true, - mirror: true, - z: 1 - } - } + }) } }, plugins: [ @@ -255,16 +208,10 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { } private getTooltipPluginConfiguration(): Partial> { - return { - ...getTooltipOptions({ - colorScheme: this.colorScheme(), - locale: this.locale(), - unit: '%' - }), - mode: 'index', - position: 'top', - xAlign: 'center', - yAlign: 'bottom' - }; + return getTimeSeriesTooltipOptions<'line'>({ + colorScheme: this.colorScheme(), + locale: this.locale(), + unit: '%' + }); } } diff --git a/apps/client/src/app/components/investment-chart/investment-chart.component.ts b/apps/client/src/app/components/investment-chart/investment-chart.component.ts index 3aa65b998..2a1ffd97c 100644 --- a/apps/client/src/app/components/investment-chart/investment-chart.component.ts +++ b/apps/client/src/app/components/investment-chart/investment-chart.component.ts @@ -1,20 +1,21 @@ import { - getTooltipOptions, + getChartBorderColor, + getChartElementsOptions, + getTimeAxisOptions, + getValueAxisOptions, getVerticalHoverLinePlugin, + getZeroLineAnnotation, transformTickToAbbreviation } from '@ghostfolio/common/chart-helper'; import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; -import { - getBackgroundColor, - getDateFormatString, - getLocale, - getTextColor, - parseDate -} from '@ghostfolio/common/helper'; +import { getLocale, parseDate } from '@ghostfolio/common/helper'; import { LineChartItem } from '@ghostfolio/common/interfaces'; import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; import { ColorScheme, GroupBy } from '@ghostfolio/common/types'; -import { registerChartConfiguration } from '@ghostfolio/ui/chart'; +import { + getTimeSeriesTooltipOptions, + registerChartConfiguration +} from '@ghostfolio/ui/chart'; import { ChangeDetectionStrategy, @@ -175,16 +176,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { data: chartData, options: { animation: false, - elements: { - line: { - tension: 0 - }, - point: { - hoverBackgroundColor: getBackgroundColor(this.colorScheme), - hoverRadius: 2, - radius: 0 - } - }, + elements: getChartElementsOptions(this.colorScheme), interaction: { intersect: false, mode: 'index' }, maintainAspectRatio: true, plugins: { @@ -212,13 +204,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { value: this.savingsRate } : undefined, - yAxis: { - borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, - borderWidth: 1, - scaleID: 'y', - type: 'line', - value: 0 - } + yAxis: getZeroLineAnnotation(this.colorScheme) } }, legend: { @@ -226,54 +212,23 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { }, tooltip: this.getTooltipPluginConfiguration(), verticalHoverLine: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` + color: getChartBorderColor(this.colorScheme) } }, responsive: true, scales: { - x: { - border: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, - width: this.groupBy ? 0 : 1 - }, - display: true, - grid: { - display: false - }, - type: 'time', - time: { - tooltipFormat: getDateFormatString(this.locale), - unit: 'year' - } - }, - y: { - border: { - display: false - }, + x: getTimeAxisOptions({ + borderWidth: this.groupBy ? 0 : 1, + colorScheme: this.colorScheme, + locale: this.locale + }), + y: getValueAxisOptions({ + colorScheme: this.colorScheme, display: !this.isInPercentage, - grid: { - color: ({ scale, tick }) => { - if ( - tick.value === 0 || - tick.value === scale.max || - tick.value === scale.min - ) { - return `rgba(${getTextColor(this.colorScheme)}, 0.1)`; - } - - return 'transparent'; - } - }, - position: 'right', - ticks: { - callback: (value: number) => { - return transformTickToAbbreviation(value); - }, - display: true, - mirror: true, - z: 1 + tickCallback: (tickValue) => { + return transformTickToAbbreviation(Number(tickValue)); } - } + }) } }, plugins: [ @@ -289,19 +244,13 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { private getTooltipPluginConfiguration(): Partial< TooltipOptions<'bar' | 'line'> > { - return { - ...getTooltipOptions({ - colorScheme: this.colorScheme, - currency: this.isInPercentage ? undefined : this.currency, - groupBy: this.groupBy, - locale: this.isInPercentage ? undefined : this.locale, - unit: this.isInPercentage ? '%' : undefined - }), - mode: 'index', - position: 'top', - xAlign: 'center', - yAlign: 'bottom' - }; + return getTimeSeriesTooltipOptions<'bar' | 'line'>({ + colorScheme: this.colorScheme, + currency: this.isInPercentage ? undefined : this.currency, + groupBy: this.groupBy, + locale: this.isInPercentage ? undefined : this.locale, + unit: this.isInPercentage ? '%' : undefined + }); } private isInFuture(aContext: ScriptableLineSegmentContext, aValue: T) { diff --git a/libs/common/src/lib/chart-helper.ts b/libs/common/src/lib/chart-helper.ts index 1f385e901..23a00ca97 100644 --- a/libs/common/src/lib/chart-helper.ts +++ b/libs/common/src/lib/chart-helper.ts @@ -1,13 +1,17 @@ import type { ElementRef } from '@angular/core'; import type { Chart, + ChartOptions, ChartType, ControllerDatasetOptions, Plugin, Point, + ScaleOptions, + Tick, TooltipOptions, TooltipPosition } from 'chart.js'; +import type { AnnotationOptions } from 'chartjs-plugin-annotation'; import { format } from 'date-fns'; import { @@ -15,6 +19,7 @@ import { DATE_FORMAT_MONTHLY, DATE_FORMAT_YEARLY, getBackgroundColor, + getDateFormatString, getLocale, getTextColor } from './helper'; @@ -36,6 +41,53 @@ export function formatGroupedDate({ return format(date, DATE_FORMAT); } +export function getChartBorderColor(colorScheme: ColorScheme) { + return `rgba(${getTextColor(colorScheme)}, 0.1)`; +} + +export function getChartElementsOptions( + colorScheme: ColorScheme +): ChartOptions<'bar' | 'line'>['elements'] { + return { + line: { + tension: 0 + }, + point: { + hoverBackgroundColor: getBackgroundColor(colorScheme), + hoverRadius: 2, + radius: 0 + } + }; +} + +export function getTimeAxisOptions({ + borderWidth = 1, + colorScheme, + display = true, + locale = getLocale() +}: { + borderWidth?: number; + colorScheme: ColorScheme; + display?: boolean; + locale?: string; +}): ScaleOptions<'time'> { + return { + display, + border: { + color: getChartBorderColor(colorScheme), + width: borderWidth + }, + grid: { + display: false + }, + time: { + tooltipFormat: getDateFormatString(locale), + unit: 'year' + }, + type: 'time' + }; +} + export function getTooltipOptions({ colorScheme, currency = '', @@ -53,7 +105,7 @@ export function getTooltipOptions({ backgroundColor: getBackgroundColor(colorScheme), bodyColor: `rgb(${getTextColor(colorScheme)})`, borderWidth: 1, - borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`, + borderColor: getChartBorderColor(colorScheme), // @ts-expect-error: no need to set all attributes in callbacks callbacks: { label: (context) => { @@ -116,6 +168,50 @@ export function getTooltipPositionerMapTop( }; } +export function getValueAxisOptions({ + colorScheme, + display = true, + highlightedValues = [], + tickCallback +}: { + colorScheme: ColorScheme; + display?: boolean; + highlightedValues?: number[]; + tickCallback: ( + tickValue: number | string, + index: number, + ticks: Tick[] + ) => string; +}): ScaleOptions<'linear'> { + return { + display, + border: { + display: false + }, + grid: { + color: ({ scale, tick }) => { + if ( + tick.value === 0 || + tick.value === scale.max || + tick.value === scale.min || + highlightedValues.includes(tick.value) + ) { + return getChartBorderColor(colorScheme); + } + + return 'transparent'; + } + }, + position: 'right', + ticks: { + display, + callback: tickCallback, + mirror: true, + z: 1 + } + }; +} + export function getVerticalHoverLinePlugin( chartCanvas: ElementRef, colorScheme: ColorScheme @@ -152,6 +248,18 @@ export function getVerticalHoverLinePlugin( }; } +export function getZeroLineAnnotation( + colorScheme: ColorScheme +): AnnotationOptions<'line'> { + return { + borderColor: getChartBorderColor(colorScheme), + borderWidth: 1, + scaleID: 'y', + type: 'line', + value: 0 + }; +} + export function transformTickToAbbreviation(value: number) { if (value === 0) { return '0'; diff --git a/libs/ui/src/lib/chart/chart.options.ts b/libs/ui/src/lib/chart/chart.options.ts new file mode 100644 index 000000000..cd2802cfb --- /dev/null +++ b/libs/ui/src/lib/chart/chart.options.ts @@ -0,0 +1,28 @@ +import { getTooltipOptions } from '@ghostfolio/common/chart-helper'; +import { ColorScheme, GroupBy } from '@ghostfolio/common/types'; + +import type { TooltipOptions } from 'chart.js'; + +import './chart.registry'; + +export function getTimeSeriesTooltipOptions({ + colorScheme, + currency, + groupBy, + locale, + unit +}: { + colorScheme: ColorScheme; + currency?: string; + groupBy?: GroupBy; + locale?: string; + unit?: string; +}): Partial> { + return { + ...getTooltipOptions({ colorScheme, currency, groupBy, locale, unit }), + mode: 'index', + position: 'top', + xAlign: 'center', + yAlign: 'bottom' + }; +} diff --git a/libs/ui/src/lib/chart/index.ts b/libs/ui/src/lib/chart/index.ts index 2a3d3b358..01597c515 100644 --- a/libs/ui/src/lib/chart/index.ts +++ b/libs/ui/src/lib/chart/index.ts @@ -1 +1,2 @@ +export * from './chart.options'; export * from './chart.registry'; diff --git a/libs/ui/src/lib/line-chart/line-chart.component.ts b/libs/ui/src/lib/line-chart/line-chart.component.ts index 92ee8e4ec..edc377fa3 100644 --- a/libs/ui/src/lib/line-chart/line-chart.component.ts +++ b/libs/ui/src/lib/line-chart/line-chart.component.ts @@ -1,14 +1,11 @@ import { - getTooltipOptions, + getChartBorderColor, + getTimeAxisOptions, + getValueAxisOptions, getVerticalHoverLinePlugin } from '@ghostfolio/common/chart-helper'; import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; -import { - getBackgroundColor, - getDateFormatString, - getLocale, - getTextColor -} from '@ghostfolio/common/helper'; +import { getBackgroundColor, getLocale } from '@ghostfolio/common/helper'; import { LineChartItem } from '@ghostfolio/common/interfaces'; import { ColorScheme } from '@ghostfolio/common/types'; @@ -38,7 +35,10 @@ import { import 'chartjs-adapter-date-fns'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { registerChartConfiguration } from '../chart'; +import { + getTimeSeriesTooltipOptions, + registerChartConfiguration +} from '../chart'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -209,49 +209,21 @@ export class GfLineChartComponent }, tooltip: this.getTooltipPluginConfiguration(), verticalHoverLine: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` + color: getChartBorderColor(this.colorScheme) } }, scales: { - x: { - border: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` - }, + x: getTimeAxisOptions({ + colorScheme: this.colorScheme, display: this.showXAxis, - grid: { - display: false - }, - time: { - tooltipFormat: getDateFormatString(this.locale), - unit: 'year' - }, - type: 'time' - }, + locale: this.locale + }), y: { - border: { - width: 0 - }, - display: this.showYAxis, - grid: { - color: ({ scale, tick }) => { - if ( - tick.value === 0 || - tick.value === scale.max || - tick.value === scale.min || - tick.value === this.yMax || - tick.value === this.yMin - ) { - return `rgba(${getTextColor(this.colorScheme)}, 0.1)`; - } - - return 'transparent'; - } - }, - max: this.yMax, - min: this.yMin, - position: 'right', - ticks: { - callback: (tickValue, index, ticks) => { + ...getValueAxisOptions({ + colorScheme: this.colorScheme, + display: this.showYAxis, + highlightedValues: [this.yMax, this.yMin], + tickCallback: (tickValue, index, ticks) => { if (index === 0 || index === ticks.length - 1) { // Only print last and first legend entry @@ -274,11 +246,10 @@ export class GfLineChartComponent } return ''; - }, - display: this.showYAxis, - mirror: true, - z: 1 - }, + } + }), + max: this.yMax, + min: this.yMin, type: 'linear' } }, @@ -321,17 +292,11 @@ export class GfLineChartComponent } private getTooltipPluginConfiguration(): Partial> { - return { - ...getTooltipOptions({ - colorScheme: this.colorScheme, - currency: this.currency, - locale: this.locale, - unit: this.unit - }), - mode: 'index', - position: 'top', - xAlign: 'center', - yAlign: 'bottom' - }; + return getTimeSeriesTooltipOptions<'line'>({ + colorScheme: this.colorScheme, + currency: this.currency, + locale: this.locale, + unit: this.unit + }); } } From 6697b8f1cb85136296c7601acb380af71e1f75cb Mon Sep 17 00:00:00 2001 From: santichausis Date: Thu, 30 Jul 2026 02:29:11 -0300 Subject: [PATCH 14/86] Task/improve language localization for Spanish (ES) (#7456) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.es.xlf | 122 ++++++++++++------------ 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcad150f7..463979740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved the tags to the overview tab of the account detail dialog (experimental) - Moved the tags to the overview tab of the holding detail dialog - Refactored the line chart components to share the common chart configuration +- Improved the language localization for Spanish (`es`) ### Fixed diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 5a402fa83..732d53c96 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -312,7 +312,7 @@ Paid - Paid + Pagado apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 129 @@ -388,7 +388,7 @@ and is driven by the efforts of its contributors - y es impulsado por los esfuerzos de sus colaboradores + y es impulsado por los esfuerzos de sus colaboradores apps/client/src/app/pages/about/overview/about-overview-page.html 50 @@ -480,7 +480,7 @@ Watch the Ghostfol.io Trailer on YouTube - Watch the Ghostfol.io Trailer on YouTube + Ver el tráiler de Ghostfol.io en YouTube apps/client/src/app/pages/landing/landing-page.html 19 @@ -752,7 +752,7 @@ Creation - Creation + Creación apps/client/src/app/components/admin-overview/admin-overview.html 185 @@ -1120,7 +1120,7 @@ Ghostfolio in Numbers: Monthly Active Users (MAU) - Ghostfolio in Numbers: Monthly Active Users (MAU) + Ghostfolio en cifras: usuarios activos mensuales (MAU) apps/client/src/app/pages/landing/landing-page.html 63 @@ -1324,7 +1324,7 @@ Coupon - Coupon + Cupón apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 134 @@ -1396,7 +1396,7 @@ The value has been copied to the clipboard - The value has been copied to the clipboard + El valor ha sido copiado al portapapeles libs/ui/src/lib/notifications/alert-dialog/alert-dialog.component.ts 46 @@ -1484,7 +1484,7 @@ Copy - Copy + Copiar libs/ui/src/lib/notifications/alert-dialog/alert-dialog.html 20 @@ -1564,7 +1564,7 @@ Financial Planning - Financial Planning + Planificación financiera libs/ui/src/lib/i18n.ts 108 @@ -1708,7 +1708,7 @@ popular - popular + popular apps/client/src/app/components/admin-settings/admin-settings.component.html 79 @@ -1932,7 +1932,7 @@ Trial - Trial + Prueba apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 133 @@ -2480,7 +2480,7 @@ {VAR_PLURAL, plural, =1 {Profile} other {Profiles}} - {VAR_PLURAL, plural, =1 {Profile} other {Profiles}} + {VAR_PLURAL, plural, =1 {Perfil} other {Perfiles}} apps/client/src/app/components/admin-market-data/admin-market-data.html 275 @@ -2720,7 +2720,7 @@ Apply current market price - Apply current market price + Aplicar el precio de mercado actual apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 238 @@ -2728,7 +2728,7 @@ Subscription History - Subscription History + Historial de suscripción apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 141 @@ -2864,7 +2864,7 @@ Close Account - Close Account + Cerrar cuenta apps/client/src/app/components/user-account-settings/user-account-settings.html 337 @@ -2884,7 +2884,7 @@ Contributors to Ghostfolio - Contributors to Ghostfolio + Colaboradores de Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 54 @@ -3272,7 +3272,7 @@ Invested Capital - Invested Capital + Capital invertido apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 173 @@ -3316,7 +3316,7 @@ Price - Price + Precio apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 176 @@ -3324,7 +3324,7 @@ Do you really want to convert this asset profile to ()? - Do you really want to convert this asset profile to ()? + ¿Seguro que quieres convertir este perfil de activo a ()? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 723 @@ -3332,7 +3332,7 @@ Data Gathering Frequency - Data Gathering Frequency + Frecuencia de recopilación de datos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 467 @@ -3496,7 +3496,7 @@ just now - just now + justo ahora apps/client/src/app/components/admin-users/admin-users.component.ts 221 @@ -3652,7 +3652,7 @@ Investments - Investments + Inversiones apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 197 @@ -3796,7 +3796,7 @@ Hourly - Hourly + Horaria apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 216 @@ -3888,7 +3888,7 @@ Expiration - Expiration + Caducidad apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 209 @@ -4416,7 +4416,7 @@ For security reasons, please delete all activities and accounts first before your Ghostfolio account can be closed. - For security reasons, please delete all activities and accounts first before your Ghostfolio account can be closed. + Por razones de seguridad, elimina primero todas las operaciones y cuentas antes de poder cerrar tu cuenta de Ghostfolio. apps/client/src/app/components/user-account-settings/user-account-settings.html 348 @@ -4520,7 +4520,7 @@ Update Activity - Update Activity + Actualizar operación libs/common/src/lib/routes/routes.ts 146 @@ -4544,7 +4544,7 @@ Total - Total + Total apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 160 @@ -4620,7 +4620,7 @@ Coupon has been created - Coupon has been created + El cupón ha sido creado apps/client/src/app/components/admin-overview/admin-overview.component.ts 224 @@ -4672,7 +4672,7 @@ Upgrade to Ghostfolio Premium - Upgrade to Ghostfolio Premium + Actualizar a Ghostfolio Premium libs/ui/src/lib/premium-indicator/premium-indicator.component.html 4 @@ -4748,7 +4748,7 @@ Web - Web + Web libs/ui/src/lib/i18n.ts 120 @@ -4820,7 +4820,7 @@ Category - Category + Categoría apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -4844,7 +4844,7 @@ An error occurred while converting the data source to . - An error occurred while converting the data source to . + Se produjo un error al convertir la fuente de datos a . apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 482 @@ -4852,7 +4852,7 @@ Ghostfolio in Numbers: Pulls on Docker Hub - Ghostfolio in Numbers: Pulls on Docker Hub + Ghostfolio en cifras: descargas en Docker Hub apps/client/src/app/pages/landing/landing-page.html 101 @@ -4892,7 +4892,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - El código fuente está disponible como software de código abierto (OSS) bajo la licencia AGPL-3.0 + El código fuente está disponible como software de código abierto (OSS) bajo la licencia AGPL-3.0 apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -4972,7 +4972,7 @@ At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. - En Ghostfolio, la transparencia está en el centro de nuestros valores. Publicamos el código fuente como software de código abierto (OSS) bajo la Licencia AGPL-3.0 y compartimos abiertamente métricas clave agregadas sobre el estado operativo de la plataforma. + En Ghostfolio, la transparencia está en el centro de nuestros valores. Publicamos el código fuente como software de código abierto (OSS) bajo la licencia AGPL-3.0 y compartimos abiertamente métricas clave agregadas sobre el estado operativo de la plataforma. apps/client/src/app/pages/open/open-page.html 7 @@ -5344,7 +5344,7 @@ Oops! Could not delete the asset profiles. - Oops! Could not delete the asset profiles. + ¡Ups! No se pudieron eliminar los perfiles de activos. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 52 @@ -5400,7 +5400,7 @@ Add Activity - Add Activity + Añadir operación libs/common/src/lib/routes/routes.ts 139 @@ -5682,7 +5682,7 @@ Stock Tracking - Stock Tracking + Seguimiento de acciones libs/ui/src/lib/i18n.ts 111 @@ -5742,7 +5742,7 @@ Convert to - Convert to + Convertir a apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 174 @@ -5762,7 +5762,7 @@ Available on - Available on + Disponible en apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 130 @@ -6082,7 +6082,7 @@ Portfolio Filters - Portfolio Filters + Filtros de cartera apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 63 @@ -6326,7 +6326,7 @@ Expires () - Expires () + Caduca () apps/client/src/app/components/admin-users/admin-users.html 34 @@ -6354,7 +6354,7 @@ Fetch market price - Fetch market price + Obtener precio de mercado libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html 40 @@ -6483,7 +6483,7 @@ Daily - Daily + Diaria apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 212 @@ -6659,7 +6659,7 @@ Clone Activity - Clone Activity + Clonar operación libs/common/src/lib/routes/routes.ts 134 @@ -6807,7 +6807,7 @@ Oops! Could not delete the asset profile. - Oops! Could not delete the asset profile. + ¡Ups! No se pudo eliminar el perfil de activo. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 51 @@ -6911,7 +6911,7 @@ Do you really want to delete these asset profiles? - Do you really want to delete these asset profiles? + ¿Seguro que quieres eliminar estos perfiles de activos? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 67 @@ -7091,7 +7091,7 @@ Tax Reporting - Tax Reporting + Informes fiscales libs/ui/src/lib/i18n.ts 112 @@ -7107,7 +7107,7 @@ Change with currency effect Change - Cambio con el efecto de la divisa Cambio + Cambio con el efecto de la divisa Cambio apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 63 @@ -7123,7 +7123,7 @@ Performance with currency effect Performance - Rendimiento con el efecto de la divisa Rendimiento + Rendimiento con el efecto de la divisa Rendimiento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 83 @@ -7171,7 +7171,7 @@ has been copied to the clipboard - ha sido copiado al portapapeles + ha sido copiado al portapapeles apps/client/src/app/components/admin-overview/admin-overview.component.ts 223 @@ -7191,7 +7191,7 @@ Compare Ghostfolio to - - Compare Ghostfolio to - + Compara Ghostfolio con - apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 32 @@ -7267,7 +7267,7 @@ Delete - Delete + Eliminar apps/client/src/app/components/admin-market-data/admin-market-data.html 270 @@ -7323,7 +7323,7 @@ Dividend Tracking - Dividend Tracking + Seguimiento de dividendos libs/ui/src/lib/i18n.ts 105 @@ -7383,7 +7383,7 @@ Investment Research - Investment Research + Investigación de inversiones libs/ui/src/lib/i18n.ts 109 @@ -7665,7 +7665,7 @@ Net Worth Tracking - Net Worth Tracking + Seguimiento del patrimonio neto libs/ui/src/lib/i18n.ts 110 @@ -7737,7 +7737,7 @@ Do you really want to convert the data source to ? - Do you really want to convert the data source to ? + ¿Seguro que quieres convertir la fuente de datos a ? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 485 @@ -7805,7 +7805,7 @@ Ghostfolio in Numbers: Stars on GitHub - Ghostfolio in Numbers: Stars on GitHub + Ghostfolio en cifras: estrellas en GitHub apps/client/src/app/pages/landing/landing-page.html 82 @@ -8127,7 +8127,7 @@ ETF Tracking - ETF Tracking + Seguimiento de ETFs libs/ui/src/lib/i18n.ts 106 @@ -8293,7 +8293,7 @@ Post to Ghostfolio on X (formerly Twitter) - Post to Ghostfolio on X (formerly Twitter) + Publicar en Ghostfolio en X (antes Twitter) apps/client/src/app/pages/about/overview/about-overview-page.html 85 @@ -8530,7 +8530,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - Si encuentras un error, deseas sugerir una mejora o una nueva funcionalidad, por favor únete a la comunidad de Ghostfolio en Slack y publica en @ghostfolio_ + Si encuentras un error, deseas sugerir una mejora o una nueva funcionalidad, por favor únete a la comunidad de Ghostfolio en Slack y publica en @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 71 From 8c2696ee4a861a9d9cc0f6a513ba9c404d4e97c5 Mon Sep 17 00:00:00 2001 From: CoderVJain <159040219+CoderVJain@users.noreply.github.com> Date: Thu, 30 Jul 2026 23:10:38 +0530 Subject: [PATCH 15/86] Task/improve language localization for UK (20260730) (#7474) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.uk.xlf | 352 ++++++++++++------------ 2 files changed, 177 insertions(+), 176 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 463979740..500d00d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved the tags to the overview tab of the holding detail dialog - Refactored the line chart components to share the common chart configuration - Improved the language localization for Spanish (`es`) +- Improved the language localization for Ukrainian (`uk`) ### Fixed diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index d0017b1b4..cee14053c 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -320,7 +320,7 @@ Fetch market price - Fetch market price + Отримати ринкову ціну libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html 40 @@ -356,7 +356,7 @@ Tax Reporting - Tax Reporting + Податкова звітність libs/ui/src/lib/i18n.ts 112 @@ -520,7 +520,7 @@ Copy - Copy + Копіювати libs/ui/src/lib/notifications/alert-dialog/alert-dialog.html 20 @@ -824,7 +824,7 @@ and is driven by the efforts of its contributors - і розвивається завдяки зусиллям своїх учасників + і розвивається завдяки зусиллям своїх учасників apps/client/src/app/pages/about/overview/about-overview-page.html 50 @@ -892,7 +892,7 @@ Category - Category + Категорія apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -916,7 +916,7 @@ An error occurred while converting the data source to . - An error occurred while converting the data source to . + Під час конвертації джерела даних на сталася помилка. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 482 @@ -932,7 +932,7 @@ Watch the Ghostfol.io Trailer on YouTube - Watch the Ghostfol.io Trailer on YouTube + Подивіться трейлер Ghostfol.io на YouTube apps/client/src/app/pages/landing/landing-page.html 19 @@ -1012,7 +1012,7 @@ Apply current market price - Apply current market price + Застосувати поточну ринкову ціну apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 238 @@ -1620,7 +1620,7 @@ Net Worth Tracking - Net Worth Tracking + Відстеження чистого капіталу libs/ui/src/lib/i18n.ts 110 @@ -2116,7 +2116,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - Вихідний код повністю доступний як програмне забезпечення з відкритим вихідним кодом (OSS) за ліцензією AGPL-3.0 + Вихідний код повністю доступний як програмне забезпечення з відкритим вихідним кодом (OSS) за ліцензією AGPL-3.0 apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -2652,7 +2652,7 @@ Investment Research - Investment Research + Інвестиційні дослідження libs/ui/src/lib/i18n.ts 109 @@ -2704,7 +2704,7 @@ Ghostfolio in Numbers: Monthly Active Users (MAU) - Ghostfolio in Numbers: Monthly Active Users (MAU) + Ghostfolio у цифрах: щомісячні активні користувачі (MAU) apps/client/src/app/pages/landing/landing-page.html 63 @@ -2752,7 +2752,7 @@ The value has been copied to the clipboard - The value has been copied to the clipboard + Значення скопійовано в буфер обміну libs/ui/src/lib/notifications/alert-dialog/alert-dialog.component.ts 46 @@ -3108,7 +3108,7 @@ Contributors to Ghostfolio - Contributors to Ghostfolio + Учасники Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 54 @@ -3152,7 +3152,7 @@ Investments - Investments + Інвестиції apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 197 @@ -3456,7 +3456,7 @@ Financial Planning - Financial Planning + Фінансове планування libs/ui/src/lib/i18n.ts 108 @@ -3740,7 +3740,7 @@ popular - popular + популярний apps/client/src/app/components/admin-settings/admin-settings.component.html 79 @@ -4009,7 +4009,7 @@ just now - just now + щойно apps/client/src/app/components/admin-users/admin-users.component.ts 221 @@ -4445,7 +4445,7 @@ At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. - У Ghostfolio прозорість є основою наших цінностей. Ми публікуємо вихідний код як відкрите програмне забезпечення (OSS) під AGPL-3.0 ліцензією та відкрито ділимося агрегованими ключовими метриками операційного стану платформи. + У Ghostfolio прозорість є основою наших цінностей. Ми публікуємо вихідний код як програмне забезпечення з відкритим вихідним кодом (OSS) за ліцензією AGPL-3.0 і відкрито ділимося агрегованими ключовими показниками роботи платформи. apps/client/src/app/pages/open/open-page.html 7 @@ -4489,7 +4489,7 @@ Convert to - Convert to + Конвертувати в apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 174 @@ -4525,7 +4525,7 @@ Job ID - Job ID + Ідентифікатор завдання apps/client/src/app/components/admin-jobs/admin-jobs.html 34 @@ -4541,7 +4541,7 @@ Available on - Available on + Доступно в apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 130 @@ -4685,7 +4685,7 @@ Find an account... - Find an account... + Знайти рахунок... libs/ui/src/lib/assistant/assistant.component.ts 447 @@ -4773,7 +4773,7 @@ or start a discussion at - or start a discussion at + або почати обговорення на apps/client/src/app/pages/about/overview/about-overview-page.html 98 @@ -4869,7 +4869,7 @@ Price - Price + Ціна apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 176 @@ -4877,7 +4877,7 @@ Do you really want to convert this asset profile to ()? - Do you really want to convert this asset profile to ()? + Ви дійсно бажаєте конвертувати цей профіль активу в ()? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 723 @@ -4993,7 +4993,7 @@ Trial - Trial + Пробний період apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 133 @@ -5001,7 +5001,7 @@ Exclude from Analysis - Exclude from Analysis + Виключити з аналізу apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 97 @@ -5109,7 +5109,7 @@ Looking for a student discount? - Looking for a student discount? + Шукаєте студентську знижку? apps/client/src/app/pages/pricing/pricing-page.html 342 @@ -5185,7 +5185,7 @@ Close Holding - Close Holding + Закрити позицію apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 449 @@ -5393,7 +5393,7 @@ Hourly - Hourly + Щогодини apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 216 @@ -5505,7 +5505,7 @@ Expiration - Expiration + Термін дії apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 209 @@ -5529,7 +5529,7 @@ Could not save asset profile - Could not save asset profile + Не вдалося зберегти профіль активу apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 675 @@ -5565,7 +5565,7 @@ has been copied to the clipboard - has been copied to the clipboard + скопійовано в буфер обміну apps/client/src/app/components/admin-overview/admin-overview.component.ts 223 @@ -5585,7 +5585,7 @@ Compare Ghostfolio to - - Compare Ghostfolio to - + Порівняйте Ghostfolio з - apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 32 @@ -5609,7 +5609,7 @@ Sustainable retirement income - Sustainable retirement income + Стабільний дохід на пенсії apps/client/src/app/pages/portfolio/fire/fire-page.html 42 @@ -5868,7 +5868,7 @@ Oops! Could not delete the asset profile. - Oops! Could not delete the asset profile. + От халепа! Не вдалося видалити профіль активу. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 51 @@ -6012,7 +6012,7 @@ Website of Thomas Kaul - Website of Thomas Kaul + Вебсайт Томаса Кауля apps/client/src/app/pages/about/overview/about-overview-page.html 45 @@ -6044,7 +6044,7 @@ Coupon has been created - Coupon has been created + Купон створено apps/client/src/app/components/admin-overview/admin-overview.component.ts 224 @@ -6120,7 +6120,7 @@ Upgrade to Ghostfolio Premium - Upgrade to Ghostfolio Premium + Перейти на Ghostfolio Premium libs/ui/src/lib/premium-indicator/premium-indicator.component.html 4 @@ -6172,7 +6172,7 @@ Financial Services - Financial Services + Фінансові послуги libs/ui/src/lib/i18n.ts 95 @@ -6180,7 +6180,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year - to use our referral link and get a Ghostfolio Premium membership for one year + щоб скористатися нашим реферальним посиланням і отримати підписку Ghostfolio Premium на один рік apps/client/src/app/pages/pricing/pricing-page.html 340 @@ -6200,7 +6200,7 @@ Delete - Delete + Видалити apps/client/src/app/components/admin-market-data/admin-market-data.html 270 @@ -6272,7 +6272,7 @@ Dividend Tracking - Dividend Tracking + Відстеження дивідендів libs/ui/src/lib/i18n.ts 105 @@ -6292,7 +6292,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio — це легкий застосунок для управління статками, який допомагає приватним особам відстежувати акції, ETF або криптовалюти та приймати обґрунтовані, засновані на даних інвестиційні рішення. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -6320,7 +6320,7 @@ Stock Tracking - Stock Tracking + Відстеження акцій libs/ui/src/lib/i18n.ts 111 @@ -6344,7 +6344,7 @@ Web - Web + Веб libs/ui/src/lib/i18n.ts 120 @@ -6572,7 +6572,7 @@ Expires () - Expires () + Закінчується () apps/client/src/app/components/admin-users/admin-users.html 34 @@ -6656,7 +6656,7 @@ Portfolio Filters - Portfolio Filters + Фільтри портфеля apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 63 @@ -6696,7 +6696,7 @@ contact us - contact us + зв'яжіться з нами apps/client/src/app/pages/pricing/pricing-page.html 336 @@ -6820,7 +6820,7 @@ Healthcare - Healthcare + Охорона здоров'я libs/ui/src/lib/i18n.ts 96 @@ -7188,7 +7188,7 @@ Ghostfolio in Numbers: Pulls on Docker Hub - Ghostfolio in Numbers: Pulls on Docker Hub + Ghostfolio у цифрах: завантаження на Docker Hub apps/client/src/app/pages/landing/landing-page.html 101 @@ -7220,7 +7220,7 @@ Everything in Basic, plus - Everything in Basic, plus + Усе, що входить у Базовий, плюс apps/client/src/app/pages/pricing/pricing-page.html 199 @@ -7284,7 +7284,7 @@ View Details - View Details + Переглянути деталі apps/client/src/app/components/admin-users/admin-users.html 220 @@ -7320,7 +7320,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + Увійти через OpenID Connect apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 57 @@ -7524,7 +7524,7 @@ Communication Services - Communication Services + Комунікаційні послуги libs/ui/src/lib/i18n.ts 91 @@ -7548,7 +7548,7 @@ If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a safe withdrawal rate (SWR) of - If you retire today, you would be able to withdraw на рік або per month, based on your total assets of та безпечним рівнем зняття коштів (SWR) у розмірі + Якщо ви вийдете на пенсію сьогодні, ви зможете знімати на рік або на місяць, виходячи із загальної суми ваших активів у розмірі та безпечної норми зняття коштів (SWR) у розмірі apps/client/src/app/pages/portfolio/fire/fire-page.html 69 @@ -7564,7 +7564,7 @@ Invested Capital - Invested Capital + Інвестований капітал apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 173 @@ -7588,7 +7588,7 @@ View Holding - View Holding + Переглянути позицію libs/ui/src/lib/activities-table/activities-table.component.html 473 @@ -7720,7 +7720,7 @@ Default Market Price - Default Market Price + Стандартна ринкова ціна apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 519 @@ -7736,7 +7736,7 @@ Do you really want to convert the data source to ? - Do you really want to convert the data source to ? + Ви дійсно бажаєте конвертувати джерело даних на ? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 485 @@ -7752,7 +7752,7 @@ HTTP Request Headers - HTTP Request Headers + Заголовки HTTP-запиту apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 532 @@ -7760,7 +7760,7 @@ end of day - end of day + кінець дня apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 259 @@ -7776,7 +7776,7 @@ Open Duck.ai - Open Duck.ai + Відкрити Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 219 @@ -7804,7 +7804,7 @@ Ghostfolio in Numbers: Stars on GitHub - Ghostfolio in Numbers: Stars on GitHub + Ghostfolio у цифрах: зірки на GitHub apps/client/src/app/pages/landing/landing-page.html 82 @@ -7840,7 +7840,7 @@ The project has been initiated by - The project has been initiated by + Проєкт було започатковано apps/client/src/app/pages/about/overview/about-overview-page.html 41 @@ -7848,7 +7848,7 @@ Copy portfolio data to clipboard for AI prompt - Copy portfolio data to clipboard for AI prompt + Скопіювати дані портфеля в буфер обміну для запиту ШІ apps/client/src/app/pages/portfolio/analysis/analysis-page.html 42 @@ -7856,7 +7856,7 @@ Copy AI prompt to clipboard for analysis - Copy AI prompt to clipboard for analysis + Скопіювати запит ШІ в буфер обміну для аналізу apps/client/src/app/pages/portfolio/analysis/analysis-page.html 67 @@ -7864,7 +7864,7 @@ Total amount - Total amount + Загальна сума apps/client/src/app/pages/portfolio/analysis/analysis-page.html 94 @@ -7872,7 +7872,7 @@ Terms and Conditions - Terms and Conditions + Умови та положення apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 15 @@ -7880,7 +7880,7 @@ Please keep your security token safe. If you lose it, you will not be able to recover your account. - Please keep your security token safe. If you lose it, you will not be able to recover your account. + Будь ласка, зберігайте свій токен безпеки в надійному місці. Якщо ви його втратите, ви не зможете відновити свій обліковий запис. apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 18 @@ -7888,7 +7888,7 @@ I understand that if I lose my security token, I cannot recover my account - I understand that if I lose my security token, I cannot recover my account + Я розумію, що якщо я втрачу свій токен безпеки, я не зможу відновити свій обліковий запис apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 28 @@ -7904,7 +7904,7 @@ Here is your security token. It is only visible once, please store and keep it in a safe place. - Here is your security token. It is only visible once, please store and keep it in a safe place. + Ось ваш токен безпеки. Він відображається лише один раз, будь ласка, збережіть його в надійному місці. apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 67 @@ -7912,7 +7912,7 @@ Security token - Security token + Токен безпеки apps/client/src/app/components/admin-users/admin-users.component.ts 273 @@ -7924,7 +7924,7 @@ Do you really want to generate a new security token for this user? - Do you really want to generate a new security token for this user? + Ви дійсно бажаєте згенерувати новий токен безпеки для цього користувача? apps/client/src/app/components/admin-users/admin-users.component.ts 278 @@ -7932,7 +7932,7 @@ Generate Security Token - Generate Security Token + Згенерувати токен безпеки apps/client/src/app/components/admin-users/admin-users.html 238 @@ -7940,7 +7940,7 @@ Terms of Service - Terms of Service + Умови надання послуг apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.html 5 @@ -7961,7 +7961,7 @@ Terms of Service - Terms of Service + Умови надання послуг apps/client/src/app/components/footer/footer.component.html 62 @@ -7973,7 +7973,7 @@ and I agree to the Terms of Service. - and I agree to the Terms of Service. + і я погоджуюсь з Умовами надання послуг. apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 34 @@ -7981,7 +7981,7 @@ () is already in use. - () is already in use. + () вже використовується. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 718 @@ -7989,7 +7989,7 @@ An error occurred while updating to (). - An error occurred while updating to (). + Під час оновлення до () сталася помилка. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 721 @@ -8005,7 +8005,7 @@ with API access for - with API access for + з доступом до API на apps/client/src/app/pages/pricing/pricing-page.html 235 @@ -8013,7 +8013,7 @@ Gather Recent Historical Market Data - Gather Recent Historical Market Data + Зібрати останні історичні ринкові дані apps/client/src/app/components/admin-market-data/admin-market-data.html 251 @@ -8021,7 +8021,7 @@ Gather All Historical Market Data - Gather All Historical Market Data + Зібрати всі історичні ринкові дані apps/client/src/app/components/admin-market-data/admin-market-data.html 256 @@ -8029,7 +8029,7 @@ Gather Historical Market Data - Gather Historical Market Data + Зібрати історичні ринкові дані apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 34 @@ -8037,7 +8037,7 @@ Data Gathering is off - Data Gathering is off + Збір даних вимкнено apps/client/src/app/components/admin-market-data/admin-market-data.html 38 @@ -8045,7 +8045,7 @@ Performance Calculation - Performance Calculation + Розрахунок прибутковості apps/client/src/app/components/user-account-settings/user-account-settings.html 31 @@ -8061,7 +8061,7 @@ Add asset to watchlist - Add asset to watchlist + Додати актив до списку спостереження apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.html 7 @@ -8085,7 +8085,7 @@ Do you really want to delete this item? - Do you really want to delete this item? + Ви дійсно бажаєте видалити цей елемент? libs/ui/src/lib/benchmark/benchmark.component.ts 142 @@ -8093,7 +8093,7 @@ Log out - Log out + Вийти apps/client/src/app/components/header/header.component.html 330 @@ -8101,7 +8101,7 @@ Calculations are based on delayed market data and may not be displayed in real-time. - Calculations are based on delayed market data and may not be displayed in real-time. + Розрахунки базуються на затриманих ринкових даних і можуть не відображатися в реальному часі. apps/client/src/app/components/home-market/home-market.html 28 @@ -8126,7 +8126,7 @@ ETF Tracking - ETF Tracking + Відстеження ETF libs/ui/src/lib/i18n.ts 106 @@ -8134,7 +8134,7 @@ Demo user account has been synced. - Demo user account has been synced. + Обліковий запис демо-користувача синхронізовано. apps/client/src/app/components/admin-overview/admin-overview.component.ts 323 @@ -8142,7 +8142,7 @@ Sync Demo User Account - Sync Demo User Account + Синхронізувати обліковий запис демо-користувача apps/client/src/app/components/admin-overview/admin-overview.html 128 @@ -8150,7 +8150,7 @@ Set up - Set up + Налаштування apps/client/src/app/pages/i18n/i18n-page.html 145 @@ -8158,7 +8158,7 @@ No emergency fund has been set up - No emergency fund has been set up + Резервний фонд не створено apps/client/src/app/pages/i18n/i18n-page.html 147 @@ -8166,7 +8166,7 @@ An emergency fund has been set up - An emergency fund has been set up + Резервний фонд створено apps/client/src/app/pages/i18n/i18n-page.html 150 @@ -8174,7 +8174,7 @@ Fee Ratio - Fee Ratio + Коефіцієнт комісій apps/client/src/app/pages/i18n/i18n-page.html 152 @@ -8182,7 +8182,7 @@ The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Комісії перевищують ${thresholdMax}% від загального обсягу ваших інвестицій (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 @@ -8190,7 +8190,7 @@ The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Комісії не перевищують ${thresholdMax}% від загального обсягу ваших інвестицій (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8198,7 +8198,7 @@ Quick Links - Quick Links + Швидкі посилання libs/ui/src/lib/assistant/assistant.html 58 @@ -8206,7 +8206,7 @@ Live Demo - Live Demo + Демоверсія apps/client/src/app/pages/landing/landing-page.html 49 @@ -8230,7 +8230,7 @@ Single Account - Single Account + Єдиний рахунок apps/client/src/app/pages/i18n/i18n-page.html 28 @@ -8238,7 +8238,7 @@ Your net worth is managed by a single account - Your net worth is managed by a single account + Ваш чистий капітал керується єдиним рахунком apps/client/src/app/pages/i18n/i18n-page.html 30 @@ -8246,7 +8246,7 @@ Your net worth is managed by ${accountsLength} accounts - Your net worth is managed by ${accountsLength} accounts + Ваш чистий капітал керується ${accountsLength} рахунками apps/client/src/app/pages/i18n/i18n-page.html 36 @@ -8284,7 +8284,7 @@ Fuel your self-hosted Ghostfolio with a powerful data provider to access 80,000+ tickers from over 50 exchanges worldwide. - Fuel your self-hosted Ghostfolio with a powerful data provider to access 80,000+ tickers from over 50 exchanges worldwide. + Підживіть свій самостійно розміщений Ghostfolio за допомогою потужного постачальника даних, щоб отримати доступ до понад 80 000 тікерів з понад 50 бірж по всьому світу. apps/client/src/app/components/admin-settings/admin-settings.component.html 16 @@ -8292,7 +8292,7 @@ Post to Ghostfolio on X (formerly Twitter) - Post to Ghostfolio on X (formerly Twitter) + Опублікувати в Ghostfolio на X (колишній Twitter) apps/client/src/app/pages/about/overview/about-overview-page.html 85 @@ -8300,7 +8300,7 @@ Get Access - Get Access + Отримати доступ apps/client/src/app/components/admin-settings/admin-settings.component.html 27 @@ -8308,7 +8308,7 @@ Learn more - Learn more + Дізнатися більше apps/client/src/app/components/admin-settings/admin-settings.component.html 38 @@ -8316,7 +8316,7 @@ Limited Offer! - Limited Offer! + Обмежена пропозиція! apps/client/src/app/components/user-account-membership/user-account-membership.html 41 @@ -8328,7 +8328,7 @@ Get extra - Get extra + Отримайте додатково apps/client/src/app/components/user-account-membership/user-account-membership.html 44 @@ -8356,7 +8356,7 @@ Current month - Current month + Поточний місяць apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 228 @@ -8372,7 +8372,7 @@ Over ${thresholdMax}% of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) - Over ${thresholdMax}% of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) + Понад ${thresholdMax}% ваших поточних інвестицій зосереджено на ${maxAccountName} (${maxInvestmentRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 17 @@ -8380,7 +8380,7 @@ The major part of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) and does not exceed ${thresholdMax}% - The major part of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) and does not exceed ${thresholdMax}% + Основна частина ваших поточних інвестицій знаходиться на ${maxAccountName} (${maxInvestmentRatio}%) і не перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 24 @@ -8396,7 +8396,7 @@ The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% - The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% + Частка акцій у ваших поточних інвестиціях (${equityValueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 43 @@ -8404,7 +8404,7 @@ The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% - The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% + Частка акцій у ваших поточних інвестиціях (${equityValueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 47 @@ -8412,7 +8412,7 @@ The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка акцій у ваших поточних інвестиціях (${equityValueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 51 @@ -8420,7 +8420,7 @@ Fixed Income - Fixed Income + Фіксований дохід apps/client/src/app/pages/i18n/i18n-page.html 55 @@ -8428,7 +8428,7 @@ The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% - The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% + Частка інструментів з фіксованим доходом у ваших поточних інвестиціях (${fixedIncomeValueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 57 @@ -8436,7 +8436,7 @@ The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% - The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% + Частка інструментів з фіксованим доходом у ваших поточних інвестиціях (${fixedIncomeValueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 61 @@ -8444,7 +8444,7 @@ The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка інструментів з фіксованим доходом у ваших поточних інвестиціях (${fixedIncomeValueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 66 @@ -8452,7 +8452,7 @@ Investment: Base Currency - Investment: Base Currency + Інвестиції: базова валюта apps/client/src/app/pages/i18n/i18n-page.html 85 @@ -8460,7 +8460,7 @@ The major part of your current investment is not in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) - The major part of your current investment is not in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) + Основна частина ваших поточних інвестицій не в базовій валюті (${baseCurrencyValueRatio}% у ${baseCurrency}) apps/client/src/app/pages/i18n/i18n-page.html 88 @@ -8468,7 +8468,7 @@ The major part of your current investment is in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) - The major part of your current investment is in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) + Основна частина ваших поточних інвестицій у базовій валюті (${baseCurrencyValueRatio}% у ${baseCurrency}) apps/client/src/app/pages/i18n/i18n-page.html 92 @@ -8484,7 +8484,7 @@ Over ${thresholdMax}% of your current investment is in ${currency} (${maxValueRatio}%) - Over ${thresholdMax}% of your current investment is in ${currency} (${maxValueRatio}%) + Понад ${thresholdMax}% ваших поточних інвестицій у ${currency} (${maxValueRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 97 @@ -8492,7 +8492,7 @@ The major part of your current investment is in ${currency} (${maxValueRatio}%) and does not exceed ${thresholdMax}% - The major part of your current investment is in ${currency} (${maxValueRatio}%) and does not exceed ${thresholdMax}% + Основна частина ваших поточних інвестицій у ${currency} (${maxValueRatio}%) і не перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 101 @@ -8513,7 +8513,7 @@ Do you really want to generate a new security token? - Do you really want to generate a new security token? + Ви дійсно бажаєте згенерувати новий токен безпеки? apps/client/src/app/components/user-account-access/user-account-access.component.ts 184 @@ -8529,7 +8529,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ + Якщо ви виявили помилку, хочете запропонувати покращення чи нову функцію, будь ласка, приєднуйтесь до спільноти Ghostfolio в Slack або напишіть у @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 71 @@ -8561,7 +8561,7 @@ Manage Asset Profile - Manage Asset Profile + Керувати профілем активу apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 477 @@ -8569,7 +8569,7 @@ Alternative Investment - Alternative Investment + Альтернативні інвестиції libs/ui/src/lib/i18n.ts 51 @@ -8585,7 +8585,7 @@ Average Unit Price - Average Unit Price + Середня ціна за одиницю apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts 140 @@ -8597,7 +8597,7 @@ Account Cluster Risks - Account Cluster Risks + Ризики концентрації рахунків apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -8605,7 +8605,7 @@ Asset Class Cluster Risks - Asset Class Cluster Risks + Ризики концентрації класів активів apps/client/src/app/pages/i18n/i18n-page.html 39 @@ -8613,7 +8613,7 @@ Currency Cluster Risks - Currency Cluster Risks + Ризики концентрації валют apps/client/src/app/pages/i18n/i18n-page.html 83 @@ -8621,7 +8621,7 @@ Economic Market Cluster Risks - Economic Market Cluster Risks + Ризики концентрації економічних ринків apps/client/src/app/pages/i18n/i18n-page.html 106 @@ -8629,7 +8629,7 @@ Emergency Fund - Emergency Fund + Резервний фонд apps/client/src/app/pages/i18n/i18n-page.html 144 @@ -8653,7 +8653,7 @@ Buying Power - Buying Power + Купівельна спроможність apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8661,7 +8661,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Your buying power is below ${thresholdMin} ${baseCurrency} + Ваша купівельна спроможність нижча за ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8669,7 +8669,7 @@ Your buying power is 0 ${baseCurrency} - Your buying power is 0 ${baseCurrency} + Ваша купівельна спроможність становить 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8677,7 +8677,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Ваша купівельна спроможність перевищує ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8685,7 +8685,7 @@ Regional Market Cluster Risks - Regional Market Cluster Risks + Ризики концентрації регіональних ринків apps/client/src/app/pages/i18n/i18n-page.html 163 @@ -8693,7 +8693,7 @@ No results found... - No results found... + Результатів не знайдено... libs/ui/src/lib/assistant/assistant.html 51 @@ -8709,7 +8709,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% + Частка розвинених ринків у ваших поточних інвестиціях (${developedMarketsValueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 112 @@ -8717,7 +8717,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% + Частка розвинених ринків у ваших поточних інвестиціях (${developedMarketsValueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 117 @@ -8725,7 +8725,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка розвинених ринків у ваших поточних інвестиціях (${developedMarketsValueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 122 @@ -8733,7 +8733,7 @@ Emerging Markets - Emerging Markets + Ринки, що розвиваються apps/client/src/app/pages/i18n/i18n-page.html 127 @@ -8741,7 +8741,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% + Частка ринків, що розвиваються, у ваших поточних інвестиціях (${emergingMarketsValueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 130 @@ -8749,7 +8749,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% + Частка ринків, що розвиваються, у ваших поточних інвестиціях (${emergingMarketsValueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 135 @@ -8757,7 +8757,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка ринків, що розвиваються, у ваших поточних інвестиціях (${emergingMarketsValueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 140 @@ -8765,7 +8765,7 @@ No accounts have been set up - No accounts have been set up + Жодного рахунку не налаштовано apps/client/src/app/pages/i18n/i18n-page.html 21 @@ -8773,7 +8773,7 @@ Your net worth is managed by 0 accounts - Your net worth is managed by 0 accounts + Ваш чистий капітал керується 0 рахунками apps/client/src/app/pages/i18n/i18n-page.html 33 @@ -8789,7 +8789,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Частка азійсько-тихоокеанського ринку у ваших поточних інвестиціях (${valueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 167 @@ -8797,7 +8797,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Частка азійсько-тихоокеанського ринку у ваших поточних інвестиціях (${valueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 171 @@ -8805,7 +8805,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка азійсько-тихоокеанського ринку у ваших поточних інвестиціях (${valueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 175 @@ -8813,7 +8813,7 @@ Emerging Markets - Emerging Markets + Ринки, що розвиваються apps/client/src/app/pages/i18n/i18n-page.html 180 @@ -8821,7 +8821,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Частка ринків, що розвиваються, у ваших поточних інвестиціях (${valueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 183 @@ -8829,7 +8829,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Частка ринків, що розвиваються, у ваших поточних інвестиціях (${valueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 187 @@ -8837,7 +8837,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка ринків, що розвиваються, у ваших поточних інвестиціях (${valueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 191 @@ -8853,7 +8853,7 @@ The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Частка європейського ринку у ваших поточних інвестиціях (${valueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 197 @@ -8861,7 +8861,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Частка європейського ринку у ваших поточних інвестиціях (${valueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 201 @@ -8869,7 +8869,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка європейського ринку у ваших поточних інвестиціях (${valueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 205 @@ -8885,7 +8885,7 @@ The Japan market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Japan market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Частка японського ринку у ваших поточних інвестиціях (${valueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 211 @@ -8893,7 +8893,7 @@ The Japan market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Japan market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Частка японського ринку у ваших поточних інвестиціях (${valueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 215 @@ -8901,7 +8901,7 @@ The Japan market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Japan market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка японського ринку у ваших поточних інвестиціях (${valueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 219 @@ -8909,7 +8909,7 @@ North America - North America + Північна Америка apps/client/src/app/pages/i18n/i18n-page.html 223 @@ -8917,7 +8917,7 @@ The North America market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The North America market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Частка північноамериканського ринку у ваших поточних інвестиціях (${valueRatio}%) перевищує ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 225 @@ -8925,7 +8925,7 @@ The North America market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The North America market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Частка північноамериканського ринку у ваших поточних інвестиціях (${valueRatio}%) нижча за ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 229 @@ -8933,7 +8933,7 @@ The North America market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The North America market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Частка північноамериканського ринку у ваших поточних інвестиціях (${valueRatio}%) перебуває в межах від ${thresholdMin}% до ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 233 @@ -8941,7 +8941,7 @@ Find Ghostfolio on GitHub - Find Ghostfolio on GitHub + Знайти Ghostfolio на GitHub apps/client/src/app/pages/about/overview/about-overview-page.html 20 @@ -8961,7 +8961,7 @@ Join the Ghostfolio Slack community - Join the Ghostfolio Slack community + Приєднатися до спільноти Ghostfolio в Slack apps/client/src/app/pages/about/overview/about-overview-page.html 78 @@ -8973,7 +8973,7 @@ Follow Ghostfolio on X (formerly Twitter) - Follow Ghostfolio on X (formerly Twitter) + Стежити за Ghostfolio в X (колишній Twitter) apps/client/src/app/pages/about/overview/about-overview-page.html 122 @@ -8981,7 +8981,7 @@ Send an e-mail - Send an e-mail + Надіслати електронний лист apps/client/src/app/pages/about/overview/about-overview-page.html 93 @@ -8993,7 +8993,7 @@ Registration Date - Registration Date + Дата реєстрації apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 56 @@ -9001,7 +9001,7 @@ Follow Ghostfolio on LinkedIn - Follow Ghostfolio on LinkedIn + Стежити за Ghostfolio в LinkedIn apps/client/src/app/pages/about/overview/about-overview-page.html 151 @@ -9009,7 +9009,7 @@ Ghostfolio is an independent & bootstrapped business - Ghostfolio is an independent & bootstrapped business + Ghostfolio — незалежний бізнес, що розвивається без зовнішнього фінансування apps/client/src/app/pages/about/overview/about-overview-page.html 161 @@ -9017,7 +9017,7 @@ Support Ghostfolio - Support Ghostfolio + Підтримати Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 170 From 1fa05f31eb168de70fbcf1fea2550dd63adfcf01 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 30 Jul 2026 19:51:37 +0200 Subject: [PATCH 16/86] Bugfix/allow removing invalid Ghostfolio API key (#7470) Allow removing invalid Ghostfolio API key --- .../admin-settings/admin-settings.component.html | 10 +++++++--- .../admin-settings/admin-settings.component.ts | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.html b/apps/client/src/app/components/admin-settings/admin-settings.component.html index c2ed2f8f5..b35f10438 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.html +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -162,7 +162,7 @@ @if (isGhostfolioDataProvider(element)) { - @if (isGhostfolioApiKeyValid === true) { + @if (hasGhostfolioApiKey) { - + - } @else if (isGhostfolioApiKeyValid === false) { + } @else if (hasGhostfolioApiKey === false) { diff --git a/libs/ui/src/lib/activities-table/activities-table.component.ts b/libs/ui/src/lib/activities-table/activities-table.component.ts index 573c8c93a..a4e7403a7 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -282,6 +282,13 @@ export class GfActivitiesTableComponent implements AfterViewInit, OnInit { ); } + public canDeleteActivities() { + return ( + (this.dataSource()?.data.length ?? 0) > 0 && + this.hasPermissionToDeleteActivity + ); + } + public isExcludedFromAnalysis(activity: Activity) { return ( (activity.account && isAccountExcluded(activity.account)) ?? @@ -314,7 +321,10 @@ export class GfActivitiesTableComponent implements AfterViewInit, OnInit { this.activitiesDeleted.emit(); }, confirmType: ConfirmationDialogType.Warn, - title: $localize`Do you really want to delete these activities?` + title: + this.totalItems === 1 + ? $localize`Do you really want to delete this activity?` + : $localize`Do you really want to delete these ${this.totalItems}:count: activities?` }); } From 81e4abbfeb8affcfbf25d189ef4ace300011685b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Jul 2026 19:41:24 +0200 Subject: [PATCH 28/86] Feature/add daily request limit (#7487) Add daily request limit --- apps/api/src/app/auth/api-key.strategy.ts | 7 ++ apps/api/src/app/auth/jwt.strategy.ts | 7 ++ .../app/portfolio/portfolio.service.spec.ts | 1 + apps/api/src/app/user/user.service.ts | 70 +++++++++++++++++-- libs/common/src/lib/config.ts | 3 + 5 files changed, 84 insertions(+), 4 deletions(-) diff --git a/apps/api/src/app/auth/api-key.strategy.ts b/apps/api/src/app/auth/api-key.strategy.ts index f9937aaa7..232a272bc 100644 --- a/apps/api/src/app/auth/api-key.strategy.ts +++ b/apps/api/src/app/auth/api-key.strategy.ts @@ -35,6 +35,13 @@ export class ApiKeyStrategy extends PassportStrategy( ); } + if (await this.userService.isDailyRequestLimitExceeded({ user })) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + await this.prismaService.analytics.upsert({ create: { user: { connect: { id: user.id } } }, update: { diff --git a/apps/api/src/app/auth/jwt.strategy.ts b/apps/api/src/app/auth/jwt.strategy.ts index c70e8fb60..189389a86 100644 --- a/apps/api/src/app/auth/jwt.strategy.ts +++ b/apps/api/src/app/auth/jwt.strategy.ts @@ -42,6 +42,13 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { ); } + if (await this.userService.isDailyRequestLimitExceeded({ user })) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + const country = countriesAndTimezones.getCountryForTimezone(timezone)?.id; diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index c16590cce..d85258f7e 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -92,6 +92,7 @@ describe('PortfolioService', () => { null, null, null, + null, null ); diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 7f3631c54..febc967d2 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -31,9 +31,12 @@ import { DEFAULT_LOCALE, PROPERTY_API_KEY_GHOSTFOLIO, PROPERTY_IS_READ_ONLY_MODE, + PROPERTY_MAX_DAILY_REQUESTS, PROPERTY_REFERRAL_PARTNERS, PROPERTY_SYSTEM_MESSAGE, - TAG_ID_EXCLUDE_FROM_ANALYSIS + TAG_ID_EXCLUDE_FROM_ANALYSIS, + THROTTLE_DAILY_KEY, + THROTTLE_DAILY_TTL } from '@ghostfolio/common/config'; import { SubscriptionType } from '@ghostfolio/common/enums'; import { @@ -50,15 +53,18 @@ import { import { UserWithSettings } from '@ghostfolio/common/types'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; +import { InjectThrottlerStorage, ThrottlerStorage } from '@nestjs/throttler'; import { Prisma, Role, Settings, User } from '@prisma/client'; import { differenceInDays, subDays } from 'date-fns'; -import { without } from 'lodash'; +import { isNil, without } from 'lodash'; import { createHmac } from 'node:crypto'; @Injectable() export class UserService { + private readonly logger = new Logger(UserService.name); + public constructor( private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, @@ -67,7 +73,9 @@ export class UserService { private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly subscriptionService: SubscriptionService, - private readonly tagService: TagService + private readonly tagService: TagService, + @InjectThrottlerStorage() + private readonly throttlerStorage: ThrottlerStorage ) {} public async count(args?: Prisma.UserCountArgs) { @@ -228,6 +236,38 @@ export class UserService { return usersWithAdminRole.length > 0; } + public async isDailyRequestLimitExceeded({ + user + }: { + user: UserWithSettings; + }) { + if (user.subscription?.type === SubscriptionType.Premium) { + return false; + } + + const maxDailyRequests = await this.getMaxDailyRequests(); + + if (maxDailyRequests === undefined) { + return false; + } + + try { + const { isBlocked } = await this.throttlerStorage.increment( + `${THROTTLE_DAILY_KEY}-${user.id}`, + THROTTLE_DAILY_TTL, + maxDailyRequests, + THROTTLE_DAILY_TTL, + THROTTLE_DAILY_KEY + ); + + return isBlocked; + } catch (error) { + this.logger.error(error); + + return false; + } + } + public async user( userWhereUniqueInput: Prisma.UserWhereUniqueInput ): Promise { @@ -782,4 +822,26 @@ export class UserService { return settings; } + + private async getMaxDailyRequests() { + const value = await this.propertyService.getByKey( + PROPERTY_MAX_DAILY_REQUESTS + ); + + if (isNil(value) || value === '') { + return undefined; + } + + const maxDailyRequests = Number(value); + + if (!Number.isInteger(maxDailyRequests) || maxDailyRequests < 0) { + this.logger.warn( + `The property ${PROPERTY_MAX_DAILY_REQUESTS} is not a non-negative integer ("${value}"), the daily request limit is not applied` + ); + + return undefined; + } + + return maxDailyRequests; + } } diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 6b070755f..890c29fbb 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -253,6 +253,7 @@ export const PROPERTY_DEMO_USER_ID = 'DEMO_USER_ID'; export const PROPERTY_IS_DATA_GATHERING_ENABLED = 'IS_DATA_GATHERING_ENABLED'; export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE'; export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED'; +export const PROPERTY_MAX_DAILY_REQUESTS = 'MAX_DAILY_REQUESTS'; export const PROPERTY_OPENROUTER_MODEL = 'OPENROUTER_MODEL'; export const PROPERTY_OPENROUTER_MODEL_WEB_FETCH = 'OPENROUTER_MODEL_WEB_FETCH'; export const PROPERTY_PROXY_ROUTES = 'PROXY_ROUTES'; @@ -326,6 +327,8 @@ export const TAG_ID_EXCLUDE_FROM_ANALYSIS = 'f2e868af-8333-459f-b161-cbc6544c24bd'; export const TAG_ID_DEMO = 'efa08cb3-9b9d-4974-ac68-db13a19c4874'; +export const THROTTLE_DAILY_KEY = 'daily'; +export const THROTTLE_DAILY_TTL = ms('1 day'); export const THROTTLE_DEFAULT_LIMIT = 10; export const THROTTLE_DEFAULT_TTL = ms('1 minute'); export const THROTTLE_SIGNUP_LIMIT = 5; From 0a01d4234a947bc4edebbf9f64257fbc2fbbc094 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Jul 2026 19:50:09 +0200 Subject: [PATCH 29/86] Bugfix/daily requests check in Ghostfolio data provider (#7485) Fix daily requests check --- .../ghostfolio/ghostfolio.controller.ts | 12 ++++++------ .../data-providers/ghostfolio/ghostfolio.service.ts | 8 ++++++-- apps/api/src/app/user/user.service.ts | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts index 5d6979acc..6e5f48d63 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts @@ -51,7 +51,7 @@ export class GhostfolioController { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); if ( - this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + this.request.user.dataProviderGhostfolioDailyRequests >= maxDailyRequests ) { throw new HttpException( getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), @@ -95,7 +95,7 @@ export class GhostfolioController { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); if ( - this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + this.request.user.dataProviderGhostfolioDailyRequests >= maxDailyRequests ) { throw new HttpException( getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), @@ -135,7 +135,7 @@ export class GhostfolioController { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); if ( - this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + this.request.user.dataProviderGhostfolioDailyRequests >= maxDailyRequests ) { throw new HttpException( getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), @@ -176,7 +176,7 @@ export class GhostfolioController { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); if ( - this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + this.request.user.dataProviderGhostfolioDailyRequests >= maxDailyRequests ) { throw new HttpException( getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), @@ -215,7 +215,7 @@ export class GhostfolioController { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); if ( - this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + this.request.user.dataProviderGhostfolioDailyRequests >= maxDailyRequests ) { throw new HttpException( getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), @@ -252,7 +252,7 @@ export class GhostfolioController { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); if ( - this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + this.request.user.dataProviderGhostfolioDailyRequests >= maxDailyRequests ) { throw new HttpException( getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts index 2c22f0c10..31d20b99e 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts @@ -326,8 +326,12 @@ export class GhostfolioService { } public async incrementDailyRequests({ userId }: { userId: string }) { - await this.prismaService.analytics.update({ - data: { + await this.prismaService.analytics.upsert({ + create: { + dataProviderGhostfolioDailyRequests: 1, + user: { connect: { id: userId } } + }, + update: { dataProviderGhostfolioDailyRequests: { increment: 1 } }, where: { userId } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index febc967d2..b706e4702 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -326,7 +326,7 @@ export class UserService { updatedAt, activityCount: analytics?.activityCount, dataProviderGhostfolioDailyRequests: - analytics?.dataProviderGhostfolioDailyRequests + analytics?.dataProviderGhostfolioDailyRequests ?? 0 }; if (user.settings) { From 9b3f7eff5fe55ffb0288a6546960901b08bbd1b7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Jul 2026 19:51:45 +0200 Subject: [PATCH 30/86] Task/improve search log output for unsupported queries (#7480) * Improve search log output for unsupported queries * Update changelog --- CHANGELOG.md | 2 ++ .../data-providers/ghostfolio/ghostfolio.service.ts | 13 +++++++------ .../services/data-provider/data-provider.service.ts | 7 +++++-- .../yahoo-finance/yahoo-finance.service.ts | 6 +++++- libs/common/src/lib/config.ts | 2 ++ libs/common/src/lib/helper.ts | 5 +++++ libs/ui/src/lib/assistant/assistant.component.ts | 9 +++++---- .../symbol-autocomplete.component.ts | 8 ++++++-- 8 files changed, 37 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 421a1bd6c..83ff99150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added the activity count to the delete menu item of the activities table - Added the activity count to the deletion confirmation dialog of the activities table - Improved the style of the type filter in the activities table component (experimental) +- Improved the search functionality by trimming the query +- Improved the log output in the search functionality of the _Yahoo Finance_ service for unsupported queries - Improved the performance of the property service by caching the properties in memory - Improved the language localization for German (`de`) diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts index 31d20b99e..b858688c2 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts @@ -17,7 +17,10 @@ import { DERIVED_CURRENCIES } from '@ghostfolio/common/config'; import { PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS } from '@ghostfolio/common/config'; -import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; +import { + getAssetProfileIdentifier, + isValidSearchQuery +} from '@ghostfolio/common/helper'; import { DataProviderGhostfolioAssetProfileResponse, DataProviderHistoricalResponse, @@ -344,7 +347,9 @@ export class GhostfolioService { }: GetSearchParams): Promise { const results: LookupResponse = { items: [] }; - if (!query) { + query = query?.trim(); + + if (!isValidSearchQuery(query)) { return results; } @@ -352,10 +357,6 @@ export class GhostfolioService { let lookupItems: LookupItem[] = []; const promises: Promise<{ items: LookupItem[] }>[] = []; - if (query?.length < 2) { - return { items: lookupItems }; - } - for (const dataProviderService of this.getDataProviderServices()) { promises.push( dataProviderService.search({ diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index e8d5f5030..4c273f2da 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -20,7 +20,8 @@ import { getCurrencyFromSymbol, getStartOfUtcDate, isCurrency, - isDerivedCurrency + isDerivedCurrency, + isValidSearchQuery } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, @@ -838,7 +839,9 @@ export class DataProviderService implements OnModuleInit { let lookupItems: LookupItem[] = []; const promises: Promise[] = []; - if (query?.length < 2) { + query = query?.trim(); + + if (!isValidSearchQuery(query)) { return { items: lookupItems }; } diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index 52fb5d5a8..364354f6b 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -330,7 +330,11 @@ export class YahooFinanceService implements DataProviderInterface { }); } } catch (error) { - this.logger.error(error); + if (error?.name === 'BadRequestError') { + this.logger.warn(`Could not search for "${query}": ${error.message}`); + } else { + this.logger.error(error); + } } return { items }; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 890c29fbb..08fb99e28 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -288,6 +288,8 @@ export const REPLACE_NAME_PARTS = [ 'Xtrackers (IE) Plc -' ]; +export const SEARCH_QUERY_MINIMUM_LENGTH = 2; + export const SECTORS = [ 'Basic Materials', 'Communication Services', diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index b2a3ab419..98f097b44 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -41,6 +41,7 @@ import { DERIVED_CURRENCIES, ghostfolioFearAndGreedIndexSymbolCryptocurrencies, ghostfolioFearAndGreedIndexSymbolStocks, + SEARCH_QUERY_MINIMUM_LENGTH, TAG_ID_EXCLUDE_FROM_ANALYSIS } from './config'; import { @@ -509,6 +510,10 @@ export function isRootCurrency(aCurrency: string) { }); } +export function isValidSearchQuery(aQuery: string) { + return aQuery?.trim().length >= SEARCH_QUERY_MINIMUM_LENGTH; +} + export function parseDate(date: string): Date | undefined { if (!date) { return undefined; diff --git a/libs/ui/src/lib/assistant/assistant.component.ts b/libs/ui/src/lib/assistant/assistant.component.ts index 471420937..9ef6c9f1c 100644 --- a/libs/ui/src/lib/assistant/assistant.component.ts +++ b/libs/ui/src/lib/assistant/assistant.component.ts @@ -202,6 +202,11 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { this.searchFormControl.valueChanges .pipe( map((searchTerm) => { + return searchTerm?.trim(); + }), + debounceTime(300), + distinctUntilChanged(), + tap(() => { this.isLoading = { accounts: true, assetProfiles: true, @@ -216,11 +221,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { }; this.changeDetectorRef.markForCheck(); - - return searchTerm?.trim(); }), - debounceTime(300), - distinctUntilChanged(), switchMap((searchTerm) => { const results = { accounts: [], diff --git a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts index cab911ef2..704c4ed44 100644 --- a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts +++ b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts @@ -41,6 +41,7 @@ import { debounceTime, distinctUntilChanged, filter, + map, switchMap } from 'rxjs/operators'; @@ -128,6 +129,9 @@ export class GfSymbolAutocompleteComponent this.control.valueChanges .pipe( + map((query) => { + return isString(query) ? query.trim() : query; + }), filter((query) => { if (query?.length === 0) { this.showDefaultOptions(); @@ -137,13 +141,13 @@ export class GfSymbolAutocompleteComponent return isString(query); }), + debounceTime(400), + distinctUntilChanged(), tap(() => { this.isLoading = true; this.changeDetectorRef.markForCheck(); }), - debounceTime(400), - distinctUntilChanged(), takeUntilDestroyed(this.destroyRef), switchMap((query: string) => { return this.dataService.fetchSymbols({ From 031b3b68c7493383c7dcf27a68e40cc159c97a99 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:38:03 +0200 Subject: [PATCH 31/86] Bugfix/deletion of activities to respect activity type and date range filter (#7492) * Respect activity type and date range filter * Update changelog --- CHANGELOG.md | 9 ++ .../app/activities/activities-filter.dto.ts | 43 ++++++++++ .../app/activities/activities.controller.ts | 83 ++++++++++--------- .../src/app/activities/activities.service.ts | 9 ++ .../src/app/activities/get-activities.dto.ts | 27 ++++++ apps/api/src/app/export/export.controller.ts | 39 ++++----- apps/api/src/app/export/export.service.ts | 6 ++ apps/api/src/app/export/get-export.dto.ts | 14 ++++ apps/client/src/app/app.component.ts | 5 +- .../activities/activities-page.component.ts | 33 +++++--- .../common/src/lib/calculation-helper.spec.ts | 24 +++++- libs/common/src/lib/calculation-helper.ts | 13 ++- libs/common/src/lib/config.ts | 14 ++++ libs/common/src/lib/types/date-range.type.ts | 12 +-- .../activities-table.component.html | 11 ++- .../activities-table.component.ts | 7 ++ libs/ui/src/lib/services/data.service.ts | 34 ++++++-- 17 files changed, 292 insertions(+), 91 deletions(-) create mode 100644 apps/api/src/app/activities/activities-filter.dto.ts create mode 100644 apps/api/src/app/activities/get-activities.dto.ts create mode 100644 apps/api/src/app/export/get-export.dto.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 83ff99150..1843d4627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added support for the date range filter in the export functionality +- Added support for the date range filter on the portfolio activities page + ### Changed - Improved the style of the tabs in the account detail dialog on mobile @@ -19,10 +24,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the search functionality by trimming the query - Improved the log output in the search functionality of the _Yahoo Finance_ service for unsupported queries - Improved the performance of the property service by caching the properties in memory +- Improved the validation of the query parameters in the activities endpoints - Improved the language localization for German (`de`) ### Fixed +- Fixed the calendar year date range in time zones with a negative _UTC_ offset +- Fixed the deletion of activities to respect the activity type filter on the activities page (experimental) +- Fixed the deletion of activities to respect the date range filter on the activities page - Fixed the static portfolio analysis rule for a portfolio with no holdings: _Asset Class Cluster Risks_ (Equity) - Fixed the static portfolio analysis rule for a portfolio with no holdings: _Asset Class Cluster Risks_ (Fixed Income) - Fixed the static portfolio analysis rule for a portfolio with no holdings: _Currency Cluster Risks_ (Investment) diff --git a/apps/api/src/app/activities/activities-filter.dto.ts b/apps/api/src/app/activities/activities-filter.dto.ts new file mode 100644 index 000000000..e5a22c020 --- /dev/null +++ b/apps/api/src/app/activities/activities-filter.dto.ts @@ -0,0 +1,43 @@ +import { DATE_RANGES } from '@ghostfolio/common/config'; +import { DateRange } from '@ghostfolio/common/types'; + +import { Type as ActivityType } from '@prisma/client'; +import { Transform, TransformFnParams } from 'class-transformer'; +import { IsEnum, IsOptional, IsString, Matches } from 'class-validator'; +import { isString } from 'lodash'; + +// A named date range or a calendar year like '2024', '2023', '2022', etc. +const DATE_RANGE_PATTERN = new RegExp(`^(${DATE_RANGES.join('|')}|\\d{4})$`); + +export class ActivitiesFilterDto { + @IsOptional() + @IsString() + accounts?: string; + + @IsEnum(ActivityType, { each: true }) + @IsOptional() + @Transform(({ value }: TransformFnParams) => { + return isString(value) ? value.split(',') : value; + }) + activityTypes?: ActivityType[]; + + @IsOptional() + @IsString() + assetClasses?: string; + + @IsOptional() + @IsString() + dataSource?: string; + + @IsOptional() + @Matches(DATE_RANGE_PATTERN) + range?: DateRange; + + @IsOptional() + @IsString() + symbol?: string; + + @IsOptional() + @IsString() + tags?: string; +} diff --git a/apps/api/src/app/activities/activities.controller.ts b/apps/api/src/app/activities/activities.controller.ts index 21dabc639..daade2a59 100644 --- a/apps/api/src/app/activities/activities.controller.ts +++ b/apps/api/src/app/activities/activities.controller.ts @@ -18,7 +18,7 @@ import { ActivityResponse } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; -import type { DateRange, RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, @@ -29,7 +29,6 @@ import { HttpException, Inject, Param, - ParseIntPipe, Post, Put, Query, @@ -38,11 +37,13 @@ import { } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { Order, Prisma, Type as ActivityType } from '@prisma/client'; +import { Order } from '@prisma/client'; import { parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; +import { ActivitiesFilterDto } from './activities-filter.dto'; import { ActivitiesService } from './activities.service'; +import { GetActivitiesDto } from './get-activities.dto'; @Controller('activities') export class ActivitiesController { @@ -60,22 +61,38 @@ export class ActivitiesController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) public async deleteActivities( - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string + @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, + @Query() query: ActivitiesFilterDto ): Promise { + if (impersonationId) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + let endDate: Date; + let startDate: Date; + + if (query.range) { + ({ endDate, startDate } = getIntervalFromDateRange({ + dateRange: query.range + })); + } + const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: query.accounts, + filterByAssetClasses: query.assetClasses, + filterByDataSource: query.dataSource, + filterBySymbol: query.symbol, + filterByTags: query.tags }); return this.activitiesService.deleteActivities({ + endDate, filters, + startDate, + types: query.activityTypes, userId: this.request.user.id }); } @@ -108,51 +125,41 @@ export class ActivitiesController { @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getAllActivities( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query('accounts') filterByAccounts?: string, - @Query('activityTypes') filterByTypes?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('range') dateRange?: DateRange, - @Query('skip', new ParseIntPipe({ optional: true })) skip?: number, - @Query('sortColumn') sortColumn?: string, - @Query('sortDirection') sortDirection?: Prisma.SortOrder, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string, - @Query('take', new ParseIntPipe({ optional: true })) take?: number + @Query() query: GetActivitiesDto ): Promise { let endDate: Date; let startDate: Date; - if (dateRange) { - ({ endDate, startDate } = getIntervalFromDateRange({ dateRange })); + if (query.range) { + ({ endDate, startDate } = getIntervalFromDateRange({ + dateRange: query.range + })); } const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: query.accounts, + filterByAssetClasses: query.assetClasses, + filterByDataSource: query.dataSource, + filterBySymbol: query.symbol, + filterByTags: query.tags }); const impersonationUserId = await this.impersonationService.validateImpersonationId(impersonationId); - const types = (filterByTypes?.split(',') as ActivityType[]) ?? []; - const userCurrency = this.request.user.settings.settings.baseCurrency; const { activities, count } = await this.activitiesService.getActivities({ endDate, filters, - skip, - sortColumn, - sortDirection, startDate, - take, - types, userCurrency, includeDrafts: true, + skip: query.skip, + sortColumn: query.sortColumn, + sortDirection: query.sortDirection, + take: query.take, + types: query.activityTypes, userId: impersonationUserId || this.request.user.id, withExcludedAccountsAndActivities: true }); diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index 7d6e822c5..da3e99312 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -361,14 +361,23 @@ export class ActivitiesService { } public async deleteActivities({ + endDate, filters, + startDate, + types, userId }: { + endDate?: Date; filters?: Filter[]; + startDate?: Date; + types?: ActivityType[]; userId: string; }): Promise { const { activities } = await this.getActivities({ + endDate, filters, + startDate, + types, userId, includeDrafts: true, userCurrency: undefined, diff --git a/apps/api/src/app/activities/get-activities.dto.ts b/apps/api/src/app/activities/get-activities.dto.ts new file mode 100644 index 000000000..0430a89c1 --- /dev/null +++ b/apps/api/src/app/activities/get-activities.dto.ts @@ -0,0 +1,27 @@ +import { Prisma } from '@prisma/client'; +import { Type } from 'class-transformer'; +import { IsIn, IsInt, IsOptional, Min } from 'class-validator'; + +import { ActivitiesFilterDto } from './activities-filter.dto'; + +export class GetActivitiesDto extends ActivitiesFilterDto { + @IsInt() + @IsOptional() + @Min(0) + @Type(() => Number) + skip?: number; + + @IsIn(Object.values(Prisma.OrderScalarFieldEnum)) + @IsOptional() + sortColumn?: keyof typeof Prisma.OrderScalarFieldEnum; + + @IsIn(['asc', 'desc'] as Prisma.SortOrder[]) + @IsOptional() + sortDirection?: Prisma.SortOrder; + + @IsInt() + @IsOptional() + @Min(0) + @Type(() => Number) + take?: number; +} diff --git a/apps/api/src/app/export/export.controller.ts b/apps/api/src/app/export/export.controller.ts index 4f4f4e6dd..f503088d4 100644 --- a/apps/api/src/app/export/export.controller.ts +++ b/apps/api/src/app/export/export.controller.ts @@ -2,6 +2,7 @@ import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard' import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; +import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { ExportResponse } from '@ghostfolio/common/interfaces'; import type { RequestWithUser } from '@ghostfolio/common/types'; @@ -15,9 +16,9 @@ import { } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { Type as ActivityType } from '@prisma/client'; import { ExportService } from './export.service'; +import { GetExportDto } from './get-export.dto'; @Controller('export') export class ExportController { @@ -31,30 +32,30 @@ export class ExportController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async export( - @Query('accounts') filterByAccounts?: string, - @Query('activityIds') filterByActivityIds?: string, - @Query('activityTypes') filterByTypes?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string - ): Promise { - const activityIds = filterByActivityIds?.split(',') ?? []; - const activityTypes = (filterByTypes?.split(',') as ActivityType[]) ?? []; + public async export(@Query() query: GetExportDto): Promise { + let endDate: Date; + let startDate: Date; + + if (query.range) { + ({ endDate, startDate } = getIntervalFromDateRange({ + dateRange: query.range + })); + } const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: query.accounts, + filterByAssetClasses: query.assetClasses, + filterByDataSource: query.dataSource, + filterBySymbol: query.symbol, + filterByTags: query.tags }); return this.exportService.export({ - activityIds, - activityTypes, + endDate, filters, + startDate, + activityIds: query.activityIds, + activityTypes: query.activityTypes, userId: this.request.user.id, userSettings: this.request.user.settings.settings }); diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index a94479562..6e920553b 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -25,13 +25,17 @@ export class ExportService { public async export({ activityIds, activityTypes, + endDate, filters, + startDate, userId, userSettings }: { activityIds?: string[]; activityTypes?: ActivityType[]; + endDate?: Date; filters?: Filter[]; + startDate?: Date; userId: string; userSettings: UserSettings; }): Promise { @@ -41,7 +45,9 @@ export class ExportService { const platformsMap: { [platformId: string]: Platform } = {}; let { activities } = await this.activitiesService.getActivities({ + endDate, filters, + startDate, userId, includeDrafts: true, sortColumn: 'date', diff --git a/apps/api/src/app/export/get-export.dto.ts b/apps/api/src/app/export/get-export.dto.ts new file mode 100644 index 000000000..5fc3c81ba --- /dev/null +++ b/apps/api/src/app/export/get-export.dto.ts @@ -0,0 +1,14 @@ +import { ActivitiesFilterDto } from '@ghostfolio/api/app/activities/activities-filter.dto'; + +import { Transform, TransformFnParams } from 'class-transformer'; +import { IsOptional, IsUUID } from 'class-validator'; +import { isString } from 'lodash'; + +export class GetExportDto extends ActivitiesFilterDto { + @IsOptional() + @IsUUID(undefined, { each: true }) + @Transform(({ value }: TransformFnParams) => { + return isString(value) ? value.split(',') : value; + }) + activityIds?: string[]; +} diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index ff67daf5e..fd17bcd6e 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -135,7 +135,10 @@ export class GfAppComponent implements OnInit { this.currentSubRoute === internalRoutes.home.subRoutes?.holdings.path) || (this.currentRoute === internalRoutes.portfolio.path && - !this.currentSubRoute)) && + !this.currentSubRoute) || + (this.currentRoute === internalRoutes.portfolio.path && + this.currentSubRoute === + internalRoutes.portfolio.subRoutes?.activities.path)) && this.user?.settings?.viewMode !== 'ZEN' ) { this.hasPermissionToChangeDateRange = true; diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts index 3362dc5d5..87da2fb84 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts @@ -10,7 +10,6 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { DateRange } from '@ghostfolio/common/types'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfFabComponent } from '@ghostfolio/ui/fab'; import { DataService } from '@ghostfolio/ui/services'; @@ -92,8 +91,14 @@ export class GfActivitiesPageComponent implements OnInit { .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { + const previousDateRange = this.getDateRange(); + this.updateUser(state.user); + if (previousDateRange !== this.getDateRange()) { + this.pageIndex = 0; + } + this.fetchActivities(); this.changeDetectorRef.markForCheck(); @@ -120,7 +125,11 @@ export class GfActivitiesPageComponent implements OnInit { protected onDeleteActivities() { this.dataService .deleteActivities({ - filters: this.userService.getFilters() + activityTypes: this.activityTypesFilter.length + ? this.activityTypesFilter + : undefined, + filters: this.userService.getFilters(), + range: this.getDateRange() }) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { @@ -159,7 +168,8 @@ export class GfActivitiesPageComponent implements OnInit { activityTypes: this.activityTypesFilter.length ? this.activityTypesFilter : undefined, - filters: this.userService.getFilters() + filters: this.userService.getFilters(), + range: this.getDateRange() }; } @@ -277,16 +287,13 @@ export class GfActivitiesPageComponent implements OnInit { this.dataSource = undefined; this.totalItems = undefined; - const dateRange = this.user?.settings?.dateRange; - const range = this.isCalendarYear(dateRange) ? dateRange : undefined; - this.dataService .fetchActivities({ - range, activityTypes: this.activityTypesFilter.length ? this.activityTypesFilter : undefined, filters: this.userService.getFilters(), + range: this.getDateRange(), skip: this.pageIndex * this.pageSize, sortColumn: this.sortColumn, sortDirection: this.sortDirection, @@ -311,12 +318,16 @@ export class GfActivitiesPageComponent implements OnInit { }); } - private isCalendarYear(dateRange?: DateRange) { - if (!dateRange) { - return false; + private getDateRange() { + const dateRange = this.user?.settings?.dateRange; + + // Omit the date ranges which do not apply to activities: '1d' spans today + // only, while 'max' would exclude drafts dated in the future + if (!dateRange || ['1d', 'max'].includes(dateRange)) { + return undefined; } - return /^\d{4}$/.test(dateRange); + return dateRange; } private updateUser(aUser: User) { diff --git a/libs/common/src/lib/calculation-helper.spec.ts b/libs/common/src/lib/calculation-helper.spec.ts index 69621ec0a..75a24edba 100644 --- a/libs/common/src/lib/calculation-helper.spec.ts +++ b/libs/common/src/lib/calculation-helper.spec.ts @@ -1,8 +1,30 @@ import { Big } from 'big.js'; +import { format } from 'date-fns'; -import { getAnnualizedPerformancePercent } from './calculation-helper'; +import { + getAnnualizedPerformancePercent, + getIntervalFromDateRange +} from './calculation-helper'; +import { DATE_FORMAT } from './helper'; describe('CalculationHelper', () => { + describe('interval from date range', () => { + it('Get interval of a calendar year', async () => { + const { endDate, startDate } = getIntervalFromDateRange({ + dateRange: '2024' + }); + + // The boundaries are expressed in the local time zone, therefore the + // calendar days must hold independently of the time zone the tests run in + expect(format(startDate, DATE_FORMAT)).toEqual('2023-12-31'); + expect(format(endDate, DATE_FORMAT)).toEqual('2024-12-31'); + + // The start date is exclusive, hence the first instant of the year is + // part of the interval + expect(startDate.getTime()).toEqual(new Date(2024, 0, 1).getTime() - 1); + }); + }); + describe('annualized performance percentage', () => { it('Get annualized performance', async () => { expect( diff --git a/libs/common/src/lib/calculation-helper.ts b/libs/common/src/lib/calculation-helper.ts index 2097fa52a..d49663d6c 100644 --- a/libs/common/src/lib/calculation-helper.ts +++ b/libs/common/src/lib/calculation-helper.ts @@ -7,6 +7,7 @@ import { startOfWeek, startOfYear, subDays, + subMilliseconds, subYears } from 'date-fns'; import { isFinite, isNumber } from 'lodash'; @@ -75,10 +76,16 @@ export function getIntervalFromDateRange(params: { break; case 'max': break; - default: + default: { // '2024', '2023', '2022', etc. - endDate = endOfYear(new Date(dateRange)); - startDate = max([startDate, new Date(dateRange)]); + const yearStartDate = new Date(Number(dateRange), 0, 1); + + // Derive the boundaries of the calendar year in the local time zone, as + // the consumers apply local time zone semantics. As the start date is + // exclusive, the last millisecond of the preceding year is used. + endDate = endOfYear(yearStartDate); + startDate = max([startDate, subMilliseconds(yearStartDate, 1)]); + } } return { endDate, startDate }; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 08fb99e28..bb4ace0c5 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -67,6 +67,20 @@ export const DATA_GATHERING_QUEUE_PRIORITY_MEDIUM = Math.round( DATA_GATHERING_QUEUE_PRIORITY_LOW / 2 ); +/** + * The named date ranges, complemented by the calendar years like '2024', + * '2023', '2022', etc. + */ +export const DATE_RANGES = [ + '1d', + '1y', + '5y', + 'max', + 'mtd', + 'wtd', + 'ytd' +] as const; + export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE = 'PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE'; export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_HIGH = 1; diff --git a/libs/common/src/lib/types/date-range.type.ts b/libs/common/src/lib/types/date-range.type.ts index 09fa3c15b..5c25cfe39 100644 --- a/libs/common/src/lib/types/date-range.type.ts +++ b/libs/common/src/lib/types/date-range.type.ts @@ -1,9 +1,3 @@ -export type DateRange = - | '1d' - | '1y' - | '5y' - | 'max' - | 'mtd' - | 'wtd' - | 'ytd' - | string; // '2024', '2023', '2022', etc. +import type { DATE_RANGES } from '../config'; + +export type DateRange = (typeof DATE_RANGES)[number] | string; // '2024', '2023', '2022', etc. diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index 1ff8496a9..ffcc77832 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -58,12 +58,19 @@ } diff --git a/libs/ui/src/lib/activities-table/activities-table.component.ts b/libs/ui/src/lib/activities-table/activities-table.component.ts index a4e7403a7..6fac6d162 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -289,6 +289,13 @@ export class GfActivitiesTableComponent implements AfterViewInit, OnInit { ); } + public canExportActivities() { + return ( + (this.dataSource()?.data.length ?? 0) > 0 && + this.hasPermissionToExportActivities + ); + } + public isExcludedFromAnalysis(activity: Activity) { return ( (activity.account && isAccountExcluded(activity.account)) ?? diff --git a/libs/ui/src/lib/services/data.service.ts b/libs/ui/src/lib/services/data.service.ts index 23c654ae6..870719702 100644 --- a/libs/ui/src/lib/services/data.service.ts +++ b/libs/ui/src/lib/services/data.service.ts @@ -329,8 +329,24 @@ export class DataService { return this.http.delete(`/api/v1/account-balance/${aId}`); } - public deleteActivities({ filters }: { filters?: Filter[] }) { - const params = this.buildFiltersAsQueryParams({ filters }); + public deleteActivities({ + activityTypes, + filters, + range + }: { + activityTypes?: string[]; + filters?: Filter[]; + range?: DateRange; + }) { + let params = this.buildFiltersAsQueryParams({ filters }); + + if (activityTypes?.length) { + params = params.append('activityTypes', activityTypes.join(',')); + } + + if (range) { + params = params.append('range', range); + } return this.http.delete('/api/v1/activities', { params }); } @@ -459,11 +475,13 @@ export class DataService { public fetchExport({ activityIds, activityTypes, - filters + filters, + range }: { activityIds?: string[]; activityTypes?: string[]; filters?: Filter[]; + range?: DateRange; } = {}) { let params = this.buildFiltersAsQueryParams({ filters }); @@ -475,6 +493,10 @@ export class DataService { params = params.append('activityTypes', activityTypes.join(',')); } + if (range) { + params = params.append('range', range); + } + return this.http.get('/api/v1/export', { params }); @@ -509,8 +531,7 @@ export class DataService { public fetchInfo(): InfoItem { const info = cloneDeep((window as any).info); const utmSource = window.localStorage.getItem('utm_source') as - | 'ios' - | 'trusted-web-activity'; + 'ios' | 'trusted-web-activity'; info.globalPermissions = filterGlobalPermissions( info.globalPermissions, @@ -949,8 +970,7 @@ export class DataService { public updateInfo() { this.http.get('/api/v1/info').subscribe((info) => { const utmSource = window.localStorage.getItem('utm_source') as - | 'ios' - | 'trusted-web-activity'; + 'ios' | 'trusted-web-activity'; info.globalPermissions = filterGlobalPermissions( info.globalPermissions, From 94c30862931caadc5465c2bd76dbcc465f9bb645 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:39:52 +0200 Subject: [PATCH 32/86] Release 3.38.0 (#7494) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1843d4627..3fe881b94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 3.38.0 - 2026-07-31 ### Added diff --git a/package-lock.json b/package-lock.json index f43ed2cbf..04a7da5a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.37.0", + "version": "3.38.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.37.0", + "version": "3.38.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index b0ca3ea20..c2bc56d4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.37.0", + "version": "3.38.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 5ccd1dece560f962042a975a7c99f24446222a8c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2026 22:26:24 +0200 Subject: [PATCH 33/86] Task/update locales (#7488) Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.de.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.es.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.fr.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.it.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.ja.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.ko.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.nl.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.pl.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.pt.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.tr.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.uk.xlf | 296 +++++++++++++----------- apps/client/src/locales/messages.xlf | 292 ++++++++++++----------- apps/client/src/locales/messages.zh.xlf | 296 +++++++++++++----------- 14 files changed, 2265 insertions(+), 1875 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index a7bb8abdd..b760aa9a3 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -383,7 +383,7 @@ Balanç de Caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -399,7 +399,7 @@ Plataforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -415,7 +415,7 @@ Balanç de Caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -439,7 +439,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -475,7 +475,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -515,11 +515,11 @@ Divisa apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -539,7 +539,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -575,11 +575,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -619,7 +619,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -659,7 +659,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -703,11 +703,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -727,7 +727,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -743,7 +743,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -867,7 +867,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -883,7 +883,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -907,7 +907,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -983,11 +983,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -999,7 +999,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -1139,11 +1139,11 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1151,7 +1151,7 @@ País apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1159,7 +1159,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1171,15 +1171,15 @@ Sectors apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1191,15 +1191,15 @@ Països apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1207,7 +1207,7 @@ Mapatge de Símbols apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1247,7 +1247,7 @@ Configuració del Proveïdor de Dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1255,7 +1255,7 @@ Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -1263,11 +1263,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1291,7 +1291,7 @@ Notes apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1307,7 +1307,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1347,7 +1347,7 @@ Nom, símbol o ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1447,7 +1447,7 @@ Recollida de Dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1459,7 +1459,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -1743,7 +1743,7 @@ Punt de Referència apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1755,7 +1755,7 @@ Sentiment del Mercat libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1835,7 +1835,7 @@ Preu Mínim apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -1843,7 +1843,7 @@ Preu Màxim apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -1851,7 +1851,7 @@ Quantitat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1859,7 +1859,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1871,7 +1871,7 @@ Rendiment del Dividend apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -1879,7 +1879,7 @@ Comissions apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1891,11 +1891,11 @@ Activitat apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -1903,7 +1903,7 @@ Informar d’un Problema amb les Dades apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2135,7 +2135,7 @@ o apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -2467,7 +2467,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2479,7 +2479,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2491,7 +2491,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2511,7 +2511,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2531,7 +2531,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2695,7 +2695,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -2719,7 +2719,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -2791,7 +2791,7 @@ Localització apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3135,7 +3135,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3251,7 +3251,7 @@ Dades de mercat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3291,11 +3291,11 @@ Visió general apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -3307,7 +3307,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -3708,7 +3708,7 @@ Explotacions apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3760,7 +3760,7 @@ Mercats apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3963,6 +3963,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Per què Ghostfolio? @@ -4212,7 +4220,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -4288,15 +4296,15 @@ Activitats apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -4312,11 +4320,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -4412,7 +4420,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -4424,11 +4432,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -4440,11 +4448,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -4796,11 +4804,11 @@ Dividend apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4864,7 +4872,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -5689,11 +5697,11 @@ Activitats d’exportació libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -5701,11 +5709,11 @@ Exporta esborranys com a ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -5713,7 +5721,7 @@ Suprimeix les activitats libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -5721,7 +5729,7 @@ Esborrany libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -5729,7 +5737,7 @@ Clonar libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -5737,15 +5745,7 @@ Exporta l’esborrany com a ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 - - - - Do you really want to delete these activities? - De veritat vols suprimir aquestes activitats? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 + 516 @@ -5753,7 +5753,11 @@ Realment vols suprimir aquesta activitat? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -5761,7 +5765,7 @@ Setmana fins avui libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -5773,7 +5777,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -5781,7 +5785,7 @@ Mes fins a la data libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -5793,7 +5797,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -5809,7 +5813,7 @@ Any fins a la data libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -5829,7 +5833,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -5841,7 +5845,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6005,7 +6009,7 @@ Interès apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6073,7 +6077,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -6101,15 +6105,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -6133,15 +6137,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -6333,7 +6337,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6341,13 +6345,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Etiqueta @@ -6417,7 +6429,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6477,7 +6489,7 @@ Patrimoni apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -6637,7 +6649,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6921,7 +6933,7 @@ View Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6977,11 +6989,11 @@ Cancel apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7033,7 +7045,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7125,7 +7137,7 @@ Change with currency effect Change apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7141,7 +7153,7 @@ Performance with currency effect Performance apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7287,6 +7299,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7607,7 +7623,7 @@ Save apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7739,7 +7755,7 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Apply apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Log out @@ -8576,7 +8604,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 0378b1068..2765b0b4c 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -66,11 +66,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -114,7 +114,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -150,7 +150,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -210,11 +210,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -254,7 +254,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -294,7 +294,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -338,7 +338,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -422,7 +422,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -462,7 +462,7 @@ Finde ein Konto... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -478,7 +478,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -502,7 +502,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -518,11 +518,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -726,7 +726,7 @@ Aktuelle Marktstimmung libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -870,7 +870,7 @@ oder apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1014,15 +1014,15 @@ Sektoren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1034,15 +1034,15 @@ Länder apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1066,7 +1066,7 @@ Datenfehler melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -1114,7 +1114,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -1126,7 +1126,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -1138,7 +1138,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -1158,7 +1158,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -1178,7 +1178,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -1358,7 +1358,7 @@ Lokalität apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1470,7 +1470,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1518,11 +1518,11 @@ Währung apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1542,7 +1542,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -1550,7 +1550,7 @@ Cash-Bestand apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1566,7 +1566,7 @@ Plattform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1798,11 +1798,11 @@ Übersicht apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -1814,7 +1814,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -1838,7 +1838,7 @@ Märkte apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -2022,7 +2022,7 @@ Positionen apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2094,7 +2094,7 @@ Name, Symbol oder ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2122,7 +2122,7 @@ Anzahl apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2130,7 +2130,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2146,7 +2146,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -2154,7 +2154,7 @@ Kommentar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2170,7 +2170,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -2178,15 +2178,15 @@ Aktivitäten apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -2202,11 +2202,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2414,7 +2414,7 @@ Geplant libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -2426,11 +2426,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -2438,11 +2438,11 @@ Aktivitäten exportieren libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -2450,11 +2450,11 @@ Geplante Aktivitäten als ICS exportieren libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -2462,7 +2462,7 @@ Kopieren libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -2470,7 +2470,7 @@ Geplante Aktivität als ICS exportieren libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -2478,7 +2478,11 @@ Möchtest du diese Aktivität wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -2578,7 +2582,7 @@ Minimum Preis apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2586,7 +2590,7 @@ Maximum Preis apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2602,11 +2606,11 @@ Sektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -2614,7 +2618,7 @@ Land apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -2622,7 +2626,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2714,7 +2718,7 @@ Verzinsung apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2854,7 +2858,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2974,7 +2978,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -2994,15 +2998,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3030,7 +3034,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -3038,13 +3042,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Tag @@ -3082,7 +3094,7 @@ Beteiligungskapital apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -3302,7 +3314,7 @@ Investiertes Kapital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3362,7 +3374,7 @@ Häufigkeit der Datensynchronisierung apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -3386,7 +3398,7 @@ Symbol Zuordnung apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -3410,11 +3422,11 @@ Dividenden apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3446,15 +3458,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3502,7 +3514,7 @@ Marktdaten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3578,11 +3590,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3954,7 +3966,7 @@ Gebühren apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4125,14 +4137,6 @@ 254 - - Do you really want to delete these activities? - Möchtest du diese Aktivitäten wirklich löschen? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - By ETF Provider Nach ETF-Anbieter @@ -4178,11 +4182,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -4590,7 +4594,7 @@ Scraper Konfiguration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -5281,6 +5285,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Warum Ghostfolio? @@ -5780,7 +5792,7 @@ In umwandeln apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5852,7 +5864,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6144,7 +6156,7 @@ Cash-Bestände apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6188,7 +6200,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6284,7 +6296,7 @@ Position abschliessen apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6324,7 +6336,7 @@ Seit Wochenbeginn libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6336,7 +6348,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6344,7 +6356,7 @@ Seit Monatsbeginn libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6356,7 +6368,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6372,7 +6384,7 @@ Seit Jahresbeginn libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6428,7 +6440,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6440,7 +6452,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6456,7 +6468,7 @@ Finanzmarktdaten synchronisieren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6468,7 +6480,7 @@ Finde eine Position... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6561,11 +6573,11 @@ Aktivität apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6573,7 +6585,7 @@ Dividendenrendite apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6629,7 +6641,7 @@ Aktivitäten löschen libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6653,7 +6665,7 @@ Springe zu einer Seite... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6709,7 +6721,7 @@ Berücksichtigen in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6945,7 +6957,7 @@ Position ansehen libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -7001,11 +7013,11 @@ Abbrechen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7057,7 +7069,7 @@ Schliessen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7149,7 +7161,7 @@ Änderung mit Währungseffekt Änderung apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7165,7 +7177,7 @@ Performance mit Währungseffekt Performance apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7311,6 +7323,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7631,7 +7647,7 @@ Speichern apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7763,7 +7779,7 @@ Standardmarktpreis apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7771,7 +7787,7 @@ Modus apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7787,7 +7803,7 @@ Selektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7795,7 +7811,7 @@ HTTP Request-Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8040,7 +8056,7 @@ Übernehmen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Ausloggen @@ -8576,7 +8604,7 @@ Anlageprofil verwalten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 87c434b2c..81e2e9968 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -67,11 +67,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -115,7 +115,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -151,7 +151,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -211,11 +211,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -255,7 +255,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -295,7 +295,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -339,7 +339,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -423,7 +423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -463,7 +463,7 @@ Buscar una cuenta... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -479,7 +479,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -503,7 +503,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -519,11 +519,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -711,7 +711,7 @@ Sentimiento del mercado libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -855,7 +855,7 @@ o apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -999,15 +999,15 @@ Sectores apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1019,15 +1019,15 @@ Países apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1051,7 +1051,7 @@ Reportar anomalía en los datos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -1099,7 +1099,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -1111,7 +1111,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -1123,7 +1123,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -1143,7 +1143,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -1163,7 +1163,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -1343,7 +1343,7 @@ Configuración regional apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1455,7 +1455,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1503,11 +1503,11 @@ Divisa apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1527,7 +1527,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -1535,7 +1535,7 @@ Saldo en efectivo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1551,7 +1551,7 @@ Plataforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1783,11 +1783,11 @@ Visión general apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -1799,7 +1799,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -1823,7 +1823,7 @@ Mercados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -2007,7 +2007,7 @@ Posiciones apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2079,7 +2079,7 @@ Nombre, símbolo o ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2107,7 +2107,7 @@ Cantidad apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2115,7 +2115,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2131,7 +2131,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -2139,7 +2139,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2155,7 +2155,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -2163,15 +2163,15 @@ Operaciones apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -2187,11 +2187,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2399,7 +2399,7 @@ Borrador libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -2411,11 +2411,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -2423,11 +2423,11 @@ Exportar operaciones libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -2435,11 +2435,11 @@ Exportar borrador como ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -2447,7 +2447,7 @@ Clonar libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -2455,7 +2455,7 @@ Exportar borrador como ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -2463,7 +2463,11 @@ ¿Seguro que quieres eliminar esta operación? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -2595,7 +2599,7 @@ Precio máximo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2635,11 +2639,11 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -2647,7 +2651,7 @@ País apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -2655,7 +2659,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2667,7 +2671,7 @@ Precio mínimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2691,7 +2695,7 @@ Interés apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2819,7 +2823,7 @@ Índice de referencia apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2959,7 +2963,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -2979,15 +2983,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3015,7 +3019,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -3023,13 +3027,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Etiqueta @@ -3067,7 +3079,7 @@ Renta variable apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -3287,7 +3299,7 @@ Capital invertido apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3347,7 +3359,7 @@ Frecuencia de recopilación de datos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -3371,7 +3383,7 @@ Mapeo de símbolos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -3387,11 +3399,11 @@ Dividendo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3431,15 +3443,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3487,7 +3499,7 @@ Datos del mercado apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3563,11 +3575,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3939,7 +3951,7 @@ Comisiones apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4102,14 +4114,6 @@ 254 - - Do you really want to delete these activities? - ¿Seguro que quieres eliminar estas operaciones? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - By ETF Provider Por proveedor de ETF @@ -4155,11 +4159,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -4567,7 +4571,7 @@ Configuración del scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -5258,6 +5262,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? ¿Por qué Ghostfolio? @@ -5757,7 +5769,7 @@ Convertir a apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5829,7 +5841,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6121,7 +6133,7 @@ Saldos de efectivo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6165,7 +6177,7 @@ Prueba apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6261,7 +6273,7 @@ Cerrar posición apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6301,7 +6313,7 @@ Semana hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6313,7 +6325,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6321,7 +6333,7 @@ Mes hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6333,7 +6345,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6349,7 +6361,7 @@ Año hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6405,7 +6417,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6417,7 +6429,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6433,7 +6445,7 @@ Recopilación de datos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6445,7 +6457,7 @@ Buscar una posición... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6538,11 +6550,11 @@ Operación apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6550,7 +6562,7 @@ Rendimiento por dividendo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6606,7 +6618,7 @@ Eliminar operaciones libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6630,7 +6642,7 @@ Saltar a una página... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6686,7 +6698,7 @@ Incluir en apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6922,7 +6934,7 @@ Ver posición libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6978,11 +6990,11 @@ Cancelar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7034,7 +7046,7 @@ Cerrar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7126,7 +7138,7 @@ Cambio con el efecto de la divisa Cambio apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7142,7 +7154,7 @@ Rendimiento con el efecto de la divisa Rendimiento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7288,6 +7300,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7608,7 +7624,7 @@ Guardar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7740,7 +7756,7 @@ Precio de mercado por defecto apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7748,7 +7764,7 @@ Modo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7764,7 +7780,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7772,7 +7788,7 @@ Encabezados de solicitud HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8017,7 +8033,7 @@ Aplicar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8108,6 +8124,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Cerrar sesión @@ -8577,7 +8605,7 @@ Gestionar perfil de activo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8605,7 +8633,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index f091a56df..8d4f182bf 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -58,11 +58,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -102,7 +102,7 @@ Plateforme apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -122,7 +122,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -158,7 +158,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -198,11 +198,11 @@ Devise apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -222,7 +222,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -230,7 +230,7 @@ Balance Cash apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -274,11 +274,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -318,7 +318,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -358,7 +358,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -394,7 +394,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -486,7 +486,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -526,7 +526,7 @@ Rechercher un compte... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -542,7 +542,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -566,7 +566,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -590,11 +590,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -606,7 +606,7 @@ Fréquence de collecte des données apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -694,11 +694,11 @@ Secteur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -706,7 +706,7 @@ Pays apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -714,7 +714,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -726,15 +726,15 @@ Secteurs apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -746,15 +746,15 @@ Pays apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -762,7 +762,7 @@ Équivalence de Symboles apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -770,7 +770,7 @@ Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -786,7 +786,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1014,7 +1014,7 @@ Référence apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1026,7 +1026,7 @@ Sentiment actuel du marché libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1174,7 +1174,7 @@ ou apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1326,7 +1326,7 @@ Prix Minimum apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -1334,7 +1334,7 @@ Prix Maximum apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -1342,7 +1342,7 @@ Quantité apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1350,7 +1350,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1362,7 +1362,7 @@ Signaler une Erreur de Données apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -1374,7 +1374,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -1386,7 +1386,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -1398,7 +1398,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -1418,7 +1418,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -1438,7 +1438,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -1674,7 +1674,7 @@ Paramètres régionaux apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1838,7 +1838,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1894,7 +1894,7 @@ Données du marché apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2118,7 +2118,7 @@ Positions apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2170,7 +2170,7 @@ Marchés apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -2210,15 +2210,15 @@ Activités apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -2234,11 +2234,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2302,7 +2302,7 @@ Nom, symbole, ou ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2334,7 +2334,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -2602,11 +2602,11 @@ Dividende apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2914,11 +2914,11 @@ Aperçu apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2930,7 +2930,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -2954,7 +2954,7 @@ Brouillon libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -2966,11 +2966,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -2978,11 +2978,11 @@ Exporter Activités libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -2990,11 +2990,11 @@ Exporter Brouillons sous ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -3002,7 +3002,7 @@ Dupliquer libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -3010,7 +3010,7 @@ Exporter Brouillon sous ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -3018,7 +3018,11 @@ Voulez-vous vraiment supprimer cette activité ? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -3074,7 +3078,7 @@ Intérêt apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3142,7 +3146,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -3162,15 +3166,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3194,15 +3198,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3266,7 +3270,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -3274,13 +3278,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Étiquette @@ -3318,7 +3330,7 @@ Capital apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -3470,7 +3482,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3562,11 +3574,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3938,7 +3950,7 @@ Frais apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4101,14 +4113,6 @@ 254 - - Do you really want to delete these activities? - Voulez-vous vraiment supprimer toutes vos activités ? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - By ETF Provider Par Émetteur d’ETF @@ -4154,11 +4158,11 @@ Lien apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -4566,7 +4570,7 @@ Configuration du Scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -5257,6 +5261,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Pourquoi Ghostfolio? @@ -5756,7 +5768,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5828,7 +5840,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6120,7 +6132,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6164,7 +6176,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6260,7 +6272,7 @@ Clôturer la Position apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6300,7 +6312,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6312,7 +6324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6320,7 +6332,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6332,7 +6344,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6348,7 +6360,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6404,7 +6416,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6416,7 +6428,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6432,7 +6444,7 @@ Collecter les données apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6444,7 +6456,7 @@ Rechercher une position... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6537,11 +6549,11 @@ Activitées apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6549,7 +6561,7 @@ Rendement en Dividende apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6605,7 +6617,7 @@ Supprimer les Activitées libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6629,7 +6641,7 @@ Aller à une page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6685,7 +6697,7 @@ Inclure dans apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6921,7 +6933,7 @@ Voir la Position libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6977,11 +6989,11 @@ Annuler apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7033,7 +7045,7 @@ Fermer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7125,7 +7137,7 @@ Variation avec taux de change appliqué Variation apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7141,7 +7153,7 @@ Performance avec taux de change appliqué Performance apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7287,6 +7299,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7607,7 +7623,7 @@ Sauvegarder apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7739,7 +7755,7 @@ Prix du marché par défaut apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Selecteur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ En-têtes de requête HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Appliquer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Se déconnecter @@ -8576,7 +8604,7 @@ Gérer le profil d’actif apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index fa0680d82..92dc8372a 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -67,11 +67,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -115,7 +115,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -151,7 +151,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -211,11 +211,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -255,7 +255,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -295,7 +295,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -339,7 +339,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -423,7 +423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -463,7 +463,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -479,7 +479,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -503,7 +503,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -519,11 +519,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -711,7 +711,7 @@ Stato d’animo attuale del mercato libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -855,7 +855,7 @@ oppure apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -999,15 +999,15 @@ Settori apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1019,15 +1019,15 @@ Paesi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1051,7 +1051,7 @@ Segnala un’anomalia dei dati apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -1099,7 +1099,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -1111,7 +1111,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -1123,7 +1123,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -1143,7 +1143,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -1163,7 +1163,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -1343,7 +1343,7 @@ Locale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1455,7 +1455,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1503,11 +1503,11 @@ Valuta apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1527,7 +1527,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -1535,7 +1535,7 @@ Saldo di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1551,7 +1551,7 @@ Piattaforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1783,11 +1783,11 @@ Panoramica apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -1799,7 +1799,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -1823,7 +1823,7 @@ Mercati apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -2007,7 +2007,7 @@ Partecipazioni apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2079,7 +2079,7 @@ Nome, simbolo o ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2107,7 +2107,7 @@ Quantità apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2115,7 +2115,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2131,7 +2131,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -2139,7 +2139,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2155,7 +2155,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -2163,15 +2163,15 @@ Attività apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -2187,11 +2187,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2399,7 +2399,7 @@ Bozza libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -2411,11 +2411,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -2423,11 +2423,11 @@ Esporta le attività libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -2435,11 +2435,11 @@ Esporta le bozze come ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -2447,7 +2447,7 @@ Clona libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -2455,7 +2455,7 @@ Esporta la bozza come ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -2463,7 +2463,11 @@ Vuoi davvero eliminare questa attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -2595,7 +2599,7 @@ Prezzo massimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2635,11 +2639,11 @@ Settore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -2647,7 +2651,7 @@ Paese apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -2655,7 +2659,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2667,7 +2671,7 @@ Prezzo minimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2691,7 +2695,7 @@ Interesse apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2819,7 +2823,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2959,7 +2963,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -2979,15 +2983,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3015,7 +3019,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -3023,13 +3027,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Etichetta @@ -3067,7 +3079,7 @@ Azione ordinaria apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -3287,7 +3299,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3347,7 +3359,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -3371,7 +3383,7 @@ Mappatura dei simboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -3387,11 +3399,11 @@ Dividendi apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3431,15 +3443,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3487,7 +3499,7 @@ Dati del mercato apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3563,11 +3575,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3939,7 +3951,7 @@ Commissioni apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4102,14 +4114,6 @@ 254 - - Do you really want to delete these activities? - Vuoi davvero eliminare tutte le tue attività? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - By ETF Provider Per fornitore di ETF @@ -4155,11 +4159,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -4567,7 +4571,7 @@ Configurazione dello scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -5258,6 +5262,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Perché Ghostfolio? @@ -5757,7 +5769,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5829,7 +5841,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6121,7 +6133,7 @@ Saldi di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6165,7 +6177,7 @@ Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6261,7 +6273,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6301,7 +6313,7 @@ Da inizio settimana libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6313,7 +6325,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6321,7 +6333,7 @@ Da inizio mese libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6333,7 +6345,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6349,7 +6361,7 @@ Da inizio anno libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6405,7 +6417,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6417,7 +6429,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6433,7 +6445,7 @@ Raccolta Dati apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6445,7 +6457,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6538,11 +6550,11 @@ Attività apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6550,7 +6562,7 @@ Rendimento da Dividendi apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6606,7 +6618,7 @@ Elimina le attività libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6630,7 +6642,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6686,7 +6698,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6922,7 +6934,7 @@ View Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6978,11 +6990,11 @@ Annulla apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7034,7 +7046,7 @@ Chiudi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7126,7 +7138,7 @@ Cambio con effetto valuta Cambia apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7142,7 +7154,7 @@ Prestazioni con effetto valuta Prestazioni apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7288,6 +7300,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7608,7 +7624,7 @@ Salva apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7740,7 +7756,7 @@ Prezzo di mercato predefinito apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7748,7 +7764,7 @@ Modalità apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7764,7 +7780,7 @@ Selettore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7772,7 +7788,7 @@ Intestazioni della richiesta HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8017,7 +8033,7 @@ Applica apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8108,6 +8124,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Esci @@ -8577,7 +8605,7 @@ Gestisci profilo risorsa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8605,7 +8633,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.ja.xlf b/apps/client/src/locales/messages.ja.xlf index 3507d24d2..14781a583 100644 --- a/apps/client/src/locales/messages.ja.xlf +++ b/apps/client/src/locales/messages.ja.xlf @@ -268,11 +268,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -312,7 +312,7 @@ 現金残高 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -328,7 +328,7 @@ プラットフォーム apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -344,7 +344,7 @@ 現金残高 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -368,7 +368,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -404,7 +404,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -444,11 +444,11 @@ 通貨 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -468,7 +468,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -504,11 +504,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -548,7 +548,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -588,7 +588,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -628,7 +628,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -644,7 +644,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -752,7 +752,7 @@ アカウントを検索... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -768,7 +768,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -792,7 +792,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -872,11 +872,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -888,7 +888,7 @@ データ収集頻度 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -1032,11 +1032,11 @@ セクター apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1044,7 +1044,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1052,7 +1052,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1064,15 +1064,15 @@ セクター apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1084,15 +1084,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1100,7 +1100,7 @@ シンボルマッピング apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1140,7 +1140,7 @@ スクレイパーの設定 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1148,7 +1148,7 @@ メモ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1164,7 +1164,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1204,7 +1204,7 @@ 名称、シンボル、またはISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1364,11 +1364,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1608,7 +1608,7 @@ ベンチマーク apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1620,7 +1620,7 @@ 現在の市場心理 libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1868,7 +1868,7 @@ または apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1948,7 +1948,7 @@ 手数料 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2044,7 +2044,7 @@ 最低価格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2052,7 +2052,7 @@ 最高価格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2060,7 +2060,7 @@ 数量 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2068,7 +2068,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2080,7 +2080,7 @@ データグリッチの報告 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2260,7 +2260,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2272,7 +2272,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2284,7 +2284,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2304,7 +2304,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2324,7 +2324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2504,7 +2504,7 @@ ロケール apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2824,7 +2824,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2928,7 +2928,7 @@ マーケットデータ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2968,11 +2968,11 @@ 概要 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2984,7 +2984,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -3368,7 +3368,7 @@ 保有資産 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3420,7 +3420,7 @@ マーケット apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3615,6 +3615,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? なぜGhostfolioなのか? @@ -3864,7 +3872,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -3940,15 +3948,15 @@ アクティビティ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -3964,11 +3972,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3987,14 +3995,6 @@ 126 - - Do you really want to delete these activities? - 本当にこれらのアクティビティを削除したいですか? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - Update activity アクティビティを更新 @@ -4072,7 +4072,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -4084,11 +4084,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -4100,11 +4100,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -4440,11 +4440,11 @@ 配当金 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5289,11 +5289,11 @@ アクティビティをエクスポート libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -5301,11 +5301,11 @@ ドラフトをICSとしてエクスポート libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -5313,7 +5313,7 @@ ドラフト libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -5321,7 +5321,7 @@ クローン libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -5329,7 +5329,7 @@ ドラフトをICSとしてエクスポート libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -5337,7 +5337,11 @@ 本当にこのアクティビティを削除したいですか? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -5469,7 +5473,7 @@ 利息 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5537,7 +5541,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -5565,15 +5569,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5597,15 +5601,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5781,7 +5785,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -5789,13 +5793,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag タグ @@ -5865,7 +5877,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -5925,7 +5937,7 @@ 株式 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -6077,7 +6089,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6197,7 +6209,7 @@ テスト apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6273,7 +6285,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6325,7 +6337,7 @@ 年初来 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6333,7 +6345,7 @@ 週初来 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6341,7 +6353,7 @@ 月初来 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6353,7 +6365,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6373,7 +6385,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6429,7 +6441,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6441,7 +6453,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6482,7 +6494,7 @@ データ収集 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6494,7 +6506,7 @@ 保有資産を検索... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6562,11 +6574,11 @@ アクティビティ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6574,7 +6586,7 @@ 配当利回り apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6630,7 +6642,7 @@ アクティビティを削除する libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6662,7 +6674,7 @@ ページにジャンプ... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6710,7 +6722,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6882,7 +6894,7 @@ View Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6970,11 +6982,11 @@ キャンセル apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7050,7 +7062,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7174,7 +7186,7 @@ Performance with currency effect Performance apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7198,7 +7210,7 @@ Change with currency effect Change apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7312,6 +7324,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7632,7 +7648,7 @@ 保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7748,7 +7764,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7764,7 +7780,7 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7772,7 +7788,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7796,7 +7812,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8041,7 +8057,7 @@ Apply apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8108,6 +8124,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Log out @@ -8577,7 +8605,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8605,7 +8633,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.ko.xlf b/apps/client/src/locales/messages.ko.xlf index 5efe7b365..5ee8c49b7 100644 --- a/apps/client/src/locales/messages.ko.xlf +++ b/apps/client/src/locales/messages.ko.xlf @@ -268,11 +268,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -312,7 +312,7 @@ 현금 잔액 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -328,7 +328,7 @@ 플랫폼 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -344,7 +344,7 @@ 현금 잔액 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -368,7 +368,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -404,7 +404,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -444,11 +444,11 @@ 통화 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -468,7 +468,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -504,11 +504,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -548,7 +548,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -588,7 +588,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -628,7 +628,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -644,7 +644,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -752,7 +752,7 @@ 계좌 검색... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -768,7 +768,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -792,7 +792,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -872,11 +872,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -888,7 +888,7 @@ 데이터 수집 빈도 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -1032,11 +1032,11 @@ 섹터 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1044,7 +1044,7 @@ 국가 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1052,7 +1052,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1064,15 +1064,15 @@ 섹터 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1084,15 +1084,15 @@ 국가 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1100,7 +1100,7 @@ 심볼 매핑 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1140,7 +1140,7 @@ 스크래퍼 설정 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1148,7 +1148,7 @@ 메모 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1164,7 +1164,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1204,7 +1204,7 @@ 이름, 심볼 또는 ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1364,11 +1364,11 @@ 링크 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1608,7 +1608,7 @@ 기준 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1620,7 +1620,7 @@ 현재 시장 분위기 libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1868,7 +1868,7 @@ 또는 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1948,7 +1948,7 @@ 수수료 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2044,7 +2044,7 @@ 최저가 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2052,7 +2052,7 @@ 최고가 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2060,7 +2060,7 @@ 수량 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2068,7 +2068,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2080,7 +2080,7 @@ 데이터 결함 보고 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2260,7 +2260,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2272,7 +2272,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2284,7 +2284,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2304,7 +2304,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2324,7 +2324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2504,7 +2504,7 @@ 장소 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2824,7 +2824,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2928,7 +2928,7 @@ 시장 데이터 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2968,11 +2968,11 @@ 개요 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2984,7 +2984,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -3368,7 +3368,7 @@ 보유 종목 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3420,7 +3420,7 @@ 시장 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3615,6 +3615,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Ghostfolio인가요? @@ -3856,7 +3864,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -3932,15 +3940,15 @@ 거래 내역 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -3956,11 +3964,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3979,14 +3987,6 @@ 126 - - Do you really want to delete these activities? - 정말로 이 거래들을 삭제하시겠습니까? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - Update activity 거래 수정 @@ -4064,7 +4064,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -4076,11 +4076,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -4092,11 +4092,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -4432,11 +4432,11 @@ 배당금 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5281,11 +5281,11 @@ 거래 내역 내보내기 libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -5293,11 +5293,11 @@ 초안을 달력 파일로 내보내기 libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -5305,7 +5305,7 @@ 초안 libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -5313,7 +5313,7 @@ 클론 libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -5321,7 +5321,7 @@ 초안을 달력 파일로 내보내기 libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -5329,7 +5329,11 @@ 정말로 이 거래를 삭제하시겠습니까? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -5461,7 +5465,7 @@ 관심 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5529,7 +5533,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -5557,15 +5561,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5589,15 +5593,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5781,7 +5785,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -5789,13 +5793,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag 꼬리표 @@ -5865,7 +5877,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -5925,7 +5937,7 @@ 주식 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -6077,7 +6089,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6197,7 +6209,7 @@ 시험 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6273,7 +6285,7 @@ 보유 포지션 종료 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6325,7 +6337,7 @@ 연초 현재 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6333,7 +6345,7 @@ 이번주 현재까지 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6341,7 +6353,7 @@ 월간 누계 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6353,7 +6365,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6373,7 +6385,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6429,7 +6441,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6441,7 +6453,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6482,7 +6494,7 @@ 데이터 수집 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6494,7 +6506,7 @@ 보유 종목 검색... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6562,11 +6574,11 @@ 거래 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6574,7 +6586,7 @@ 배당수익률 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6630,7 +6642,7 @@ 거래 삭제 libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6662,7 +6674,7 @@ 페이지 이동... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6710,7 +6722,7 @@ 포함 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6882,7 +6894,7 @@ 보유 종목 보기 libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6970,11 +6982,11 @@ 취소 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7050,7 +7062,7 @@ 닫다 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7174,7 +7186,7 @@ 환율 효과 반영 수익률 수익률 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7198,7 +7210,7 @@ 환율 효과 반영 변동 변동 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7312,6 +7324,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7632,7 +7648,7 @@ 구하다 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7748,7 +7764,7 @@ 방법 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7764,7 +7780,7 @@ 기본 시장 가격 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7772,7 +7788,7 @@ 선택자 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7796,7 +7812,7 @@ HTTP 요청 헤더 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8041,7 +8057,7 @@ 적용하다 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8108,6 +8124,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out 로그아웃 @@ -8577,7 +8605,7 @@ 자산 프로필 관리 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8605,7 +8633,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 585a06f79..fccb994a9 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -66,11 +66,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -114,7 +114,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -150,7 +150,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -210,11 +210,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -254,7 +254,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -294,7 +294,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -338,7 +338,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -422,7 +422,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -462,7 +462,7 @@ Zoek een account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -478,7 +478,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -502,7 +502,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -518,11 +518,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -710,7 +710,7 @@ Huidig marktsentiment libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -854,7 +854,7 @@ of apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -998,15 +998,15 @@ Sectoren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1018,15 +1018,15 @@ Landen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1050,7 +1050,7 @@ Gegevensstoring melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -1098,7 +1098,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -1110,7 +1110,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -1122,7 +1122,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -1142,7 +1142,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -1162,7 +1162,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -1342,7 +1342,7 @@ Locatie apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1454,7 +1454,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1502,11 +1502,11 @@ Valuta apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1526,7 +1526,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -1534,7 +1534,7 @@ Saldo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1550,7 +1550,7 @@ Platform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1782,11 +1782,11 @@ Overzicht apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -1798,7 +1798,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -1822,7 +1822,7 @@ Markten apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -2006,7 +2006,7 @@ Posities apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2078,7 +2078,7 @@ Naam, symbool of ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2106,7 +2106,7 @@ Hoeveelheid apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2114,7 +2114,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2130,7 +2130,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -2138,7 +2138,7 @@ Opmerking apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2154,7 +2154,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -2162,15 +2162,15 @@ Activiteiten apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -2186,11 +2186,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2398,7 +2398,7 @@ Concept libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -2410,11 +2410,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -2422,11 +2422,11 @@ Activiteiten exporteren libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -2434,11 +2434,11 @@ Concept exporteren als ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -2446,7 +2446,7 @@ Kloon libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -2454,7 +2454,7 @@ Concept exporteren als ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -2462,7 +2462,11 @@ Wil je deze activiteit echt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -2594,7 +2598,7 @@ Maximale prijs apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2634,11 +2638,11 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -2646,7 +2650,7 @@ Land apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -2654,7 +2658,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2666,7 +2670,7 @@ Minimale prijs apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2690,7 +2694,7 @@ Rente apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2818,7 +2822,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2958,7 +2962,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -2978,15 +2982,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3014,7 +3018,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -3022,13 +3026,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Label @@ -3066,7 +3078,7 @@ Equity apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -3286,7 +3298,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3346,7 +3358,7 @@ Frequentie van gegevensverzameling apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -3370,7 +3382,7 @@ Symbool toewijzen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -3386,11 +3398,11 @@ Dividend apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3430,15 +3442,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3486,7 +3498,7 @@ Marktgegevens apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3562,11 +3574,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3938,7 +3950,7 @@ Kosten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4101,14 +4113,6 @@ 254 - - Do you really want to delete these activities? - Weet je zeker dat je alle activiteiten wilt verwijderen? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - By ETF Provider Per ETF-aanbieder @@ -4154,11 +4158,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -4566,7 +4570,7 @@ Scraper instellingen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -5257,6 +5261,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Waarom Ghostfolio? @@ -5756,7 +5768,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5828,7 +5840,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6120,7 +6132,7 @@ Contant Saldo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6164,7 +6176,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6260,7 +6272,7 @@ Sluit Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6300,7 +6312,7 @@ Week tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6312,7 +6324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6320,7 +6332,7 @@ Maand tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6332,7 +6344,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6348,7 +6360,7 @@ Jaar tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6404,7 +6416,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6416,7 +6428,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6432,7 +6444,7 @@ Data Verzamelen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6444,7 +6456,7 @@ Zoek een positie... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6537,11 +6549,11 @@ Activiteit apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6549,7 +6561,7 @@ Dividendrendement apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6605,7 +6617,7 @@ Verwijder Activiteiten libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6629,7 +6641,7 @@ Ga naar een pagina... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6685,7 +6697,7 @@ Opnemen in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6921,7 +6933,7 @@ Bekijk Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6977,11 +6989,11 @@ Annuleren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7033,7 +7045,7 @@ Sluiten apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7125,7 +7137,7 @@ Verandering met valuta-effect Verandering apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7141,7 +7153,7 @@ Prestaties met valuta-effect Prestaties apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7287,6 +7299,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7607,7 +7623,7 @@ Opslaan apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7739,7 +7755,7 @@ Standaard Marktprijs apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Modus apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Kiezer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ HTTP Verzoek Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Toepassen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Uitloggen @@ -8576,7 +8604,7 @@ Beheer activaprofiel apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index d07646ecd..502faf9f6 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -267,11 +267,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -311,7 +311,7 @@ Saldo Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -327,7 +327,7 @@ Platforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -359,7 +359,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -395,7 +395,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -435,11 +435,11 @@ Waluta apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -459,7 +459,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -495,11 +495,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -539,7 +539,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -579,7 +579,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -619,7 +619,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -635,7 +635,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -743,7 +743,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -759,7 +759,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -783,7 +783,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -863,11 +863,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -879,7 +879,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -999,11 +999,11 @@ Sektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1011,7 +1011,7 @@ Kraj apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1019,7 +1019,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1031,15 +1031,15 @@ Sektory apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1051,15 +1051,15 @@ Kraje apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1067,7 +1067,7 @@ Mapowanie Symboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1107,7 +1107,7 @@ Konfiguracja Scrapera apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1115,7 +1115,7 @@ Notatka apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1131,7 +1131,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1171,7 +1171,7 @@ Nazwa, symbol lub ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1331,11 +1331,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1575,7 +1575,7 @@ Poziom Odniesienia (Benchmark) apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1587,7 +1587,7 @@ Obecny Nastrój Rynkowy libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1835,7 +1835,7 @@ lub apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1915,7 +1915,7 @@ Opłaty apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2011,7 +2011,7 @@ Cena Minimalna apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2019,7 +2019,7 @@ Cena Maksymalna apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2027,7 +2027,7 @@ Ilość apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2035,7 +2035,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2047,7 +2047,7 @@ Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2227,7 +2227,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2239,7 +2239,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2251,7 +2251,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2271,7 +2271,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2291,7 +2291,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2471,7 +2471,7 @@ Ustawienia Regionalne apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2791,7 +2791,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2895,7 +2895,7 @@ Dane Rynkowe apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2935,11 +2935,11 @@ Przegląd apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2951,7 +2951,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -3335,7 +3335,7 @@ Inwestycje apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3387,7 +3387,7 @@ Rynki apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3582,6 +3582,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Dlaczego Ghostfolio? @@ -3823,7 +3831,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -3899,15 +3907,15 @@ Aktywności apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -3923,11 +3931,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3946,14 +3954,6 @@ 126 - - Do you really want to delete these activities? - Czy na pewno chcesz usunąć te aktywności? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - Update activity Aktualizuj aktywność @@ -4031,7 +4031,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -4043,11 +4043,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -4059,11 +4059,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -4399,11 +4399,11 @@ Dywidenda apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5228,11 +5228,11 @@ Eksportuj Działalności libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -5240,11 +5240,11 @@ Eksportuj Wersje Robocze jako ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -5252,7 +5252,7 @@ Przygotuj Wstępną Wersję libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -5260,7 +5260,7 @@ Sklonuj libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -5268,7 +5268,7 @@ Eksportuj Wersję Roboczą jako ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -5276,7 +5276,11 @@ Czy na pewno chcesz usunąć tę działalność? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -5384,7 +5388,7 @@ Odsetki apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5452,7 +5456,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -5480,15 +5484,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5512,15 +5516,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5704,7 +5708,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -5712,13 +5716,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Tag @@ -5788,7 +5800,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -5848,7 +5860,7 @@ Kapitał apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -6000,7 +6012,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6120,7 +6132,7 @@ Salda Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6164,7 +6176,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6260,7 +6272,7 @@ Zamknij pozycję apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6300,7 +6312,7 @@ Dotychczasowy tydzień libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6312,7 +6324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6320,7 +6332,7 @@ Od początku miesiąca libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6332,7 +6344,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6348,7 +6360,7 @@ Od początku roku libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6404,7 +6416,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6416,7 +6428,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6432,7 +6444,7 @@ Gromadzenie Danych apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6444,7 +6456,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6537,11 +6549,11 @@ Aktywność apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6549,7 +6561,7 @@ Dochód z Dywidendy apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6605,7 +6617,7 @@ Usuń aktywności libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6629,7 +6641,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6685,7 +6697,7 @@ Uwzględnij w apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6921,7 +6933,7 @@ Podgląd inwestycji libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6977,11 +6989,11 @@ Anuluj apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7033,7 +7045,7 @@ Zamknij apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7125,7 +7137,7 @@ Zmiana z efektem walutowym Zmiana apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7141,7 +7153,7 @@ Wydajność z efektem walutowym Wydajność apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7287,6 +7299,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7607,7 +7623,7 @@ Zapisz apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7739,7 +7755,7 @@ Domyślna cena rynkowa apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Tryb apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Selektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ Nagłówki żądań HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Zatwierdź apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Wyloguj się @@ -8576,7 +8604,7 @@ Zarządzaj profilem aktywów apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 8aa2ecf93..a89f05adb 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -58,11 +58,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -102,7 +102,7 @@ Plataforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -122,7 +122,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -158,7 +158,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -198,11 +198,11 @@ Moeda apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -222,7 +222,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -230,7 +230,7 @@ Saldo disponível em dinheiro apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -274,11 +274,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -318,7 +318,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -358,7 +358,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -394,7 +394,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -486,7 +486,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -526,7 +526,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -542,7 +542,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -566,7 +566,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -590,11 +590,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -858,7 +858,7 @@ Referência apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -870,7 +870,7 @@ Tom do Mercado Atual libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1026,7 +1026,7 @@ ou apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1178,7 +1178,7 @@ Preço Mínimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -1186,7 +1186,7 @@ Preço Máximo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -1194,7 +1194,7 @@ Quantidade apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1202,7 +1202,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1222,11 +1222,11 @@ Setor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1234,7 +1234,7 @@ País apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1242,7 +1242,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1254,15 +1254,15 @@ Setores apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1274,15 +1274,15 @@ Países apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1306,7 +1306,7 @@ Dados do Relatório com Problema apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -1354,7 +1354,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -1366,7 +1366,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -1378,7 +1378,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -1398,7 +1398,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -1418,7 +1418,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -1666,7 +1666,7 @@ Localidade apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1830,7 +1830,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2086,11 +2086,11 @@ Visão geral apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2102,7 +2102,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -2126,7 +2126,7 @@ Mercados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -2166,15 +2166,15 @@ Atividades apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -2190,11 +2190,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2258,7 +2258,7 @@ Nome, símbolo or ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2290,7 +2290,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -2298,7 +2298,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2314,7 +2314,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -2606,7 +2606,7 @@ Posições apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2846,7 +2846,7 @@ Rascunho libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -2858,11 +2858,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -2870,11 +2870,11 @@ Exportar Atividades libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -2882,11 +2882,11 @@ Exportar Rascunhos como ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -2894,7 +2894,7 @@ Clonar libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -2902,7 +2902,7 @@ Exportar Rascunho como ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -2910,7 +2910,11 @@ Deseja realmente eliminar esta atividade? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -2966,7 +2970,7 @@ Juros apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2998,7 +3002,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -3018,15 +3022,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3094,7 +3098,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -3102,13 +3106,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Marcador @@ -3146,7 +3158,7 @@ Ações apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -3298,7 +3310,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3358,7 +3370,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -3382,7 +3394,7 @@ Mapeamento de Símbolo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -3398,7 +3410,7 @@ Dados de Mercado apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3462,11 +3474,11 @@ Dividendos apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -3506,15 +3518,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -3562,11 +3574,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3938,7 +3950,7 @@ Taxas apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4101,14 +4113,6 @@ 254 - - Do you really want to delete these activities? - Deseja mesmo eliminar estas atividades? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - By ETF Provider Por Prestador de ETF @@ -4154,11 +4158,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -4566,7 +4570,7 @@ Configuração do raspador apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -5257,6 +5261,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Por que Ghostfolio? @@ -5756,7 +5768,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5828,7 +5840,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6120,7 +6132,7 @@ Saldos de caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6164,7 +6176,7 @@ Teste apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6260,7 +6272,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6300,7 +6312,7 @@ Semana até agora libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6312,7 +6324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6320,7 +6332,7 @@ Do mês até a data libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6332,7 +6344,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6348,7 +6360,7 @@ No acumulado do ano libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6404,7 +6416,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6416,7 +6428,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6432,7 +6444,7 @@ Coleta de dados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6444,7 +6456,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6537,11 +6549,11 @@ Atividade apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6549,7 +6561,7 @@ Rendimento de dividendos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6605,7 +6617,7 @@ Excluir atividades libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6629,7 +6641,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6685,7 +6697,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6921,7 +6933,7 @@ View Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6977,11 +6989,11 @@ Cancelar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7033,7 +7045,7 @@ Fechar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7125,7 +7137,7 @@ Change with currency effect Change apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7141,7 +7153,7 @@ Performance with currency effect Performance apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7287,6 +7299,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7607,7 +7623,7 @@ Guardar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7739,7 +7755,7 @@ Preço de mercado padrão apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Apply apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Log out @@ -8576,7 +8604,7 @@ Gerenciar perfil de ativos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 8630fea58..dce74dcfa 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -239,11 +239,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -283,7 +283,7 @@ Nakit Bakiye apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -299,7 +299,7 @@ Platform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -319,7 +319,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -355,7 +355,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -395,11 +395,11 @@ Para Birimi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -419,7 +419,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -455,11 +455,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -499,7 +499,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -539,7 +539,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -575,7 +575,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -667,7 +667,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -707,7 +707,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -723,7 +723,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -747,7 +747,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -815,11 +815,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -831,7 +831,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -919,11 +919,11 @@ Sektör apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -931,7 +931,7 @@ Ülke apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -939,7 +939,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -951,15 +951,15 @@ Sektörler apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -971,15 +971,15 @@ Ülkeler apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -987,7 +987,7 @@ Sembol Eşleştirme apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1027,7 +1027,7 @@ Veri Toplayıcı Yapılandırması apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1035,7 +1035,7 @@ Not apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1051,7 +1051,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1067,7 +1067,7 @@ Ad, sembol ya da ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1227,11 +1227,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1423,7 +1423,7 @@ Karşılaştırma Ölçütü apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1435,7 +1435,7 @@ Piyasa Psikolojisi libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1683,7 +1683,7 @@ veya apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1847,7 +1847,7 @@ Asgari Fiyat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -1855,7 +1855,7 @@ Azami Fiyat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -1863,7 +1863,7 @@ Miktar apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1871,7 +1871,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1883,7 +1883,7 @@ Komisyon apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1895,7 +1895,7 @@ Rapor Veri Sorunu apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2075,7 +2075,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2087,7 +2087,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2099,7 +2099,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2119,7 +2119,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2139,7 +2139,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2319,7 +2319,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2391,7 +2391,7 @@ Piyasa Verileri apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2431,11 +2431,11 @@ Özet apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2447,7 +2447,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -2843,7 +2843,7 @@ Varlıklar apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2895,7 +2895,7 @@ Piyasalar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3066,6 +3066,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Neden Ghostfolio? @@ -3323,15 +3331,15 @@ İşlemler apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -3347,11 +3355,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3370,14 +3378,6 @@ 126 - - Do you really want to delete these activities? - Tüm işlemlerinizi silmeyi gerçekten istiyor musunuz? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - Update activity İşlemi Güncelle @@ -3431,7 +3431,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -3443,11 +3443,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -3459,11 +3459,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -3807,11 +3807,11 @@ Temettü apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4768,7 +4768,7 @@ Yerel Ayarlar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -4936,11 +4936,11 @@ İşlemleri Dışa Aktar libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -4948,11 +4948,11 @@ Taslakları ICS Olarak Dışa Aktar libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -4960,7 +4960,7 @@ Taslak libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -4968,7 +4968,7 @@ Klonla libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -4976,7 +4976,7 @@ Taslakları ICS Olarak Dışa Aktar libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -4984,7 +4984,11 @@ TBu işlemi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -5072,7 +5076,7 @@ Faiz apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5140,7 +5144,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -5168,15 +5172,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5200,15 +5204,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5392,7 +5396,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -5400,13 +5404,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Etiket @@ -5520,7 +5532,7 @@ Menkul Kıymet apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -5672,7 +5684,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5764,7 +5776,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -5836,7 +5848,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -6120,7 +6132,7 @@ Nakit Bakiyeleri apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -6164,7 +6176,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6260,7 +6272,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6300,7 +6312,7 @@ Hafta içi libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6312,7 +6324,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6320,7 +6332,7 @@ Ay içi libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6332,7 +6344,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6348,7 +6360,7 @@ Yıl içi libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6404,7 +6416,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6416,7 +6428,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6432,7 +6444,7 @@ Veri Toplama apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6444,7 +6456,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6537,11 +6549,11 @@ Etkinlik apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6549,7 +6561,7 @@ Temettü Getiri apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6605,7 +6617,7 @@ Etkinlikleri Sil libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6629,7 +6641,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6685,7 +6697,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6921,7 +6933,7 @@ View Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6977,11 +6989,11 @@ İptal Et apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7033,7 +7045,7 @@ Kapat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7125,7 +7137,7 @@ Kur farkı etkisiyle değişim Değişim apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7141,7 +7153,7 @@ Kur farkı etkisiyle performans Performans apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7287,6 +7299,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7607,7 +7623,7 @@ Kaydet apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7739,7 +7755,7 @@ Varsayılan Piyasa Fiyatı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Mod apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Seçici apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ HTTP İstek Başlıkları apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Uygula apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Oturumu kapat @@ -8576,7 +8604,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index fa110490a..be6b41b0f 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -407,7 +407,7 @@ Баланс готівки apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -423,7 +423,7 @@ Платформа apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -439,7 +439,7 @@ Баланс готівки apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -463,7 +463,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -499,7 +499,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -539,11 +539,11 @@ Валюта apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -563,7 +563,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -599,11 +599,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -643,7 +643,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -683,7 +683,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -727,11 +727,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -751,7 +751,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -775,7 +775,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -963,7 +963,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -979,11 +979,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -995,7 +995,7 @@ Частота збору даних apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -1119,11 +1119,11 @@ Сектор apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1131,7 +1131,7 @@ Країна apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1139,7 +1139,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1151,15 +1151,15 @@ Сектори apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1171,15 +1171,15 @@ Країни apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1187,7 +1187,7 @@ Зіставлення символів apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1227,7 +1227,7 @@ Конфігурація скребка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1235,7 +1235,7 @@ Тест apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -1243,11 +1243,11 @@ URL apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1271,7 +1271,7 @@ Примітка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1287,7 +1287,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1335,7 +1335,7 @@ Назва, символ або ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1435,7 +1435,7 @@ Збір даних apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1447,7 +1447,7 @@ Знайти актив... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -1655,7 +1655,7 @@ або apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1859,7 +1859,7 @@ Порівняльний показник apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1871,7 +1871,7 @@ Поточний ринковий настрій libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1951,7 +1951,7 @@ Зміна з урахуванням валютного ефекту Зміна apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -1967,7 +1967,7 @@ Прибутковість з урахуванням валютного ефекту валюти Прибутковість apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -1975,7 +1975,7 @@ Мінімальна ціна apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -1983,7 +1983,7 @@ Максимальна ціна apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -1991,7 +1991,7 @@ Кількість apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1999,7 +1999,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2011,7 +2011,7 @@ Дохідність дивіденду apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -2019,7 +2019,7 @@ Комісії apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2031,11 +2031,11 @@ Активність apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -2043,7 +2043,7 @@ Повідомити про збій даних apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2415,7 +2415,7 @@ Зберегти apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2695,7 +2695,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2707,7 +2707,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2719,7 +2719,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2739,7 +2739,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2759,7 +2759,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2995,7 +2995,7 @@ Перейти до сторінки... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -3019,7 +3019,7 @@ Включити до apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -3091,7 +3091,7 @@ Локалізація apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3423,7 +3423,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3539,7 +3539,7 @@ Ринкові дані apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -3579,11 +3579,11 @@ Огляд apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -3595,7 +3595,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -4004,7 +4004,7 @@ Активи apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -4056,7 +4056,7 @@ Ринки apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -4259,6 +4259,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? Чому Ghostfolio? @@ -4508,7 +4516,7 @@ Конвертувати в apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -4584,15 +4592,15 @@ Активності apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -4608,11 +4616,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -4704,7 +4712,7 @@ Знайти рахунок... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -4720,7 +4728,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -4736,7 +4744,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -4748,11 +4756,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -4764,11 +4772,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -5136,11 +5144,11 @@ Дивіденди apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5204,7 +5212,7 @@ Закрити позицію apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6221,6 +6229,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -6479,11 +6491,11 @@ Експорт активності libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -6491,11 +6503,11 @@ Експортувати чернетки як ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -6503,7 +6515,7 @@ Видалити активності libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6511,7 +6523,7 @@ Чернетка libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -6519,7 +6531,7 @@ Клонувати libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -6527,15 +6539,7 @@ Експортувати чернетку як ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 - - - - Do you really want to delete these activities? - Ви дійсно хочете видалити ці дії? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 + 516 @@ -6543,7 +6547,11 @@ Ви дійсно хочете видалити цю активність? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -6551,7 +6559,7 @@ Тиждень до дати libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6563,7 +6571,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6571,7 +6579,7 @@ Місяць до дати libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6583,7 +6591,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6599,7 +6607,7 @@ Рік до дати libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6619,7 +6627,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6631,7 +6639,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6795,7 +6803,7 @@ Відсотки apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6887,7 +6895,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -6915,15 +6923,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -6947,15 +6955,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -6979,11 +6987,11 @@ Скасувати apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7043,7 +7051,7 @@ Закрити apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7263,7 +7271,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7271,13 +7279,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag Тег @@ -7363,7 +7379,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -7423,7 +7439,7 @@ Капітал apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -7583,7 +7599,7 @@ Інвестований капітал apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -7607,7 +7623,7 @@ Переглянути позицію libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -7739,7 +7755,7 @@ Стандартна ринкова ціна apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7747,7 +7763,7 @@ Режим apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7763,7 +7779,7 @@ Селектор apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7771,7 +7787,7 @@ Заголовки HTTP-запиту apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8016,7 +8032,7 @@ Застосувати apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8107,6 +8123,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out Вийти @@ -8576,7 +8604,7 @@ Керувати профілем активу apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8604,7 +8632,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 528c478ca..c0297b1fa 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -251,11 +251,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -290,7 +290,7 @@ Cash Balance apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -305,7 +305,7 @@ Platform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -320,7 +320,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -342,7 +342,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -378,7 +378,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -415,11 +415,11 @@ Currency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -439,7 +439,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -474,11 +474,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -517,7 +517,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -556,7 +556,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -592,7 +592,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -607,7 +607,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -703,7 +703,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -718,7 +718,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -740,7 +740,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -812,11 +812,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -827,7 +827,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -955,18 +955,18 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 Country apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -974,7 +974,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -985,15 +985,15 @@ Sectors apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1004,22 +1004,22 @@ Countries apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 Symbol Mapping apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1054,14 +1054,14 @@ Scraper Configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1077,7 +1077,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1112,7 +1112,7 @@ Name, symbol or ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1254,11 +1254,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1474,7 +1474,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1485,7 +1485,7 @@ Current Market Mood libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1709,7 +1709,7 @@ or apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1783,7 +1783,7 @@ Fees apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1869,21 +1869,21 @@ Minimum Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 Maximum Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 Quantity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1891,7 +1891,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1902,7 +1902,7 @@ Report Data Glitch apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2070,7 +2070,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2081,7 +2081,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2092,7 +2092,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2110,7 +2110,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2128,7 +2128,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2287,7 +2287,7 @@ Locale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2579,7 +2579,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2673,7 +2673,7 @@ Market Data apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2710,11 +2710,11 @@ Overview apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2726,7 +2726,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -3084,7 +3084,7 @@ Holdings apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3133,7 +3133,7 @@ Markets apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3309,6 +3309,13 @@ 84 + + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? @@ -3527,7 +3534,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -3594,15 +3601,15 @@ Activities apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -3618,11 +3625,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3641,13 +3648,6 @@ 126 - - Do you really want to delete these activities? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - Update activity @@ -3716,7 +3716,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -3727,11 +3727,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -3742,11 +3742,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -4045,11 +4045,11 @@ Dividend apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -4812,50 +4812,54 @@ Export Activities libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 Export Drafts as ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 Draft libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 Clone libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 Export Draft as ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -4971,7 +4975,7 @@ Interest apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5035,7 +5039,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -5061,15 +5065,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5092,15 +5096,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5259,7 +5263,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -5267,13 +5271,20 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag @@ -5336,7 +5347,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -5390,7 +5401,7 @@ Equity apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -5524,7 +5535,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5633,7 +5644,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -5701,7 +5712,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -5747,21 +5758,21 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 Week to date libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 Month to date libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -5772,7 +5783,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -5790,7 +5801,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -5841,7 +5852,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -5852,7 +5863,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -5889,7 +5900,7 @@ Data Gathering apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -5900,7 +5911,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -5960,18 +5971,18 @@ Activity apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6020,7 +6031,7 @@ Delete Activities libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6048,7 +6059,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6090,7 +6101,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6247,7 +6258,7 @@ View Holding libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6325,11 +6336,11 @@ Cancel apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6401,7 +6412,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6515,7 +6526,7 @@ Performance with currency effect Performance apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -6536,7 +6547,7 @@ Change with currency effect Change apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -6638,6 +6649,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -6924,7 +6939,7 @@ Save apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7031,7 +7046,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7045,14 +7060,14 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7073,7 +7088,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -7292,7 +7307,7 @@ Apply apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -7352,6 +7367,17 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out @@ -7768,7 +7794,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -7793,7 +7819,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 9cb1e72ba..a70be75d6 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -268,11 +268,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 5 + 7 libs/ui/src/lib/activities-table/activities-table.component.html - 183 + 197 @@ -312,7 +312,7 @@ 现金余额 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 54 + 55 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -328,7 +328,7 @@ 平台 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 112 + 113 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -344,7 +344,7 @@ 现金余额 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 169 + 170 @@ -368,7 +368,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 332 + 333 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -404,7 +404,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 161 + 175 libs/ui/src/lib/benchmark/benchmark.component.html @@ -444,11 +444,11 @@ 货币 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 216 + 217 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 339 + 340 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -468,7 +468,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 303 + 317 @@ -504,11 +504,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 284 + 298 libs/ui/src/lib/activities-table/activities-table.component.html - 320 + 334 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -548,7 +548,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 483 + 497 @@ -588,7 +588,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 513 + 527 libs/ui/src/lib/benchmark/benchmark.component.html @@ -628,7 +628,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 486 + 487 @@ -644,7 +644,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 197 + 198 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -752,7 +752,7 @@ Find an account... libs/ui/src/lib/assistant/assistant.component.ts - 447 + 448 @@ -768,7 +768,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 206 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -792,7 +792,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 113 + 114 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html @@ -872,11 +872,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 235 + 236 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 221 + 222 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -888,7 +888,7 @@ Data Gathering Frequency apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 467 + 468 @@ -1008,11 +1008,11 @@ 行业 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 280 + 281 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 270 + 271 @@ -1020,7 +1020,7 @@ 国家 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 295 + 296 apps/client/src/app/components/admin-users/admin-users.html @@ -1028,7 +1028,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 284 + 285 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1040,15 +1040,15 @@ 行业 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 301 + 302 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 420 + 421 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 290 + 291 apps/client/src/app/pages/public/public-page.html @@ -1060,15 +1060,15 @@ 国家 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 311 + 312 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 431 + 432 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 302 + 303 @@ -1076,7 +1076,7 @@ 代码映射 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 409 + 410 @@ -1116,7 +1116,7 @@ 刮削配置 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 510 @@ -1124,7 +1124,7 @@ 笔记 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 455 + 456 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1140,7 +1140,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 370 + 384 @@ -1180,7 +1180,7 @@ 名称、代码或 ISIN apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 133 + 134 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1340,11 +1340,11 @@ 网址 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 442 + 443 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 588 + 589 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1584,7 +1584,7 @@ 基准 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 401 + 402 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1596,7 +1596,7 @@ 当前市场情绪 libs/ui/src/lib/fear-and-greed-index/fear-and-greed-index.component.html - 22 + 23 @@ -1844,7 +1844,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 167 + 168 apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1924,7 +1924,7 @@ 费用 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 210 + 211 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2020,7 +2020,7 @@ 最低价格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 131 + 132 @@ -2028,7 +2028,7 @@ 最高价格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 149 + 150 @@ -2036,7 +2036,7 @@ 数量 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 159 + 160 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2044,7 +2044,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 213 + 227 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -2056,7 +2056,7 @@ 报告数据故障 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 463 + 464 @@ -2236,7 +2236,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 366 @@ -2248,7 +2248,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -2260,7 +2260,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -2280,7 +2280,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -2300,7 +2300,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 415 + 416 @@ -2480,7 +2480,7 @@ 语言环境 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 547 + 548 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2800,7 +2800,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 395 + 396 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -2904,7 +2904,7 @@ 市场数据 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 417 + 418 libs/common/src/lib/routes/routes.ts @@ -2944,11 +2944,11 @@ 概述 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 41 + 42 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 114 + 115 apps/client/src/app/components/header/header.component.html @@ -2960,7 +2960,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 47 + 48 apps/client/src/app/pages/admin/admin-page.component.ts @@ -3344,7 +3344,7 @@ 持仓 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 126 + 127 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3396,7 +3396,7 @@ 市场 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 403 + 404 apps/client/src/app/components/footer/footer.component.html @@ -3591,6 +3591,14 @@ 84 + + Do you really want to delete these activities? + Do you really want to delete these activities? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 334 + + Why Ghostfolio? 为什么使用Ghostfolio @@ -3840,7 +3848,7 @@ Convert to apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 174 + 175 @@ -3916,15 +3924,15 @@ 活动 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 102 + 103 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 137 + 138 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 244 + 245 apps/client/src/app/components/admin-overview/admin-overview.html @@ -3940,11 +3948,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 233 + 234 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 361 + 362 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -3963,14 +3971,6 @@ 126 - - Do you really want to delete these activities? - 您确定要删除这些活动吗? - - libs/ui/src/lib/activities-table/activities-table.component.ts - 317 - - Update activity 更新活动 @@ -4048,7 +4048,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 237 + 251 @@ -4060,11 +4060,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 28 + 30 libs/ui/src/lib/activities-table/activities-table.component.html - 406 + 420 @@ -4076,11 +4076,11 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 52 + 54 libs/ui/src/lib/activities-table/activities-table.component.html - 420 + 434 @@ -4416,11 +4416,11 @@ 股息 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 91 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 188 + 189 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5265,11 +5265,11 @@ 导出活动记录 libs/ui/src/lib/activities-table/activities-table.component.html - 64 + 72 libs/ui/src/lib/activities-table/activities-table.component.html - 434 + 448 @@ -5277,11 +5277,11 @@ 将汇票导出为 ICS libs/ui/src/lib/activities-table/activities-table.component.html - 77 + 86 libs/ui/src/lib/activities-table/activities-table.component.html - 447 + 461 @@ -5289,7 +5289,7 @@ 草稿 libs/ui/src/lib/activities-table/activities-table.component.html - 167 + 181 @@ -5297,7 +5297,7 @@ 克隆 libs/ui/src/lib/activities-table/activities-table.component.html - 492 + 506 @@ -5305,7 +5305,7 @@ 将汇票导出为 ICS libs/ui/src/lib/activities-table/activities-table.component.html - 502 + 516 @@ -5313,7 +5313,11 @@ 您确实要删除此活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 327 + 333 + + + libs/ui/src/lib/activities-table/activities-table.component.ts + 344 @@ -5445,7 +5449,7 @@ 利息 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 78 + 79 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -5513,7 +5517,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 335 + 349 libs/ui/src/lib/i18n.ts @@ -5541,15 +5545,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 253 + 254 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 349 + 350 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 244 + 245 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5573,15 +5577,15 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 262 + 263 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 365 + 366 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 253 + 254 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -5757,7 +5761,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 186 + 187 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -5765,13 +5769,21 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 322 + 323 libs/ui/src/lib/i18n.ts 35 + + Export + Export + + libs/ui/src/lib/activities-table/activities-table.component.html + 68 + + Tag 标签 @@ -5841,7 +5853,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 261 + 275 libs/ui/src/lib/i18n.ts @@ -5901,7 +5913,7 @@ 股权 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 66 + 67 libs/ui/src/lib/i18n.ts @@ -6053,7 +6065,7 @@ Invested Capital apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 173 + 174 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -6173,7 +6185,7 @@ 测试 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 606 + 607 @@ -6249,7 +6261,7 @@ 关闭持仓 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 450 + 451 @@ -6301,7 +6313,7 @@ 今年迄今为止 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 378 @@ -6309,7 +6321,7 @@ 本周至今 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6317,7 +6329,7 @@ 本月至今 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6329,7 +6341,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 373 + 374 @@ -6349,7 +6361,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 369 + 370 @@ -6405,7 +6417,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 388 @@ -6417,7 +6429,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 409 + 410 @@ -6458,7 +6470,7 @@ 数据收集 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 629 + 630 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6470,7 +6482,7 @@ Find a holding... libs/ui/src/lib/assistant/assistant.component.ts - 448 + 449 @@ -6538,11 +6550,11 @@ 活动 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 100 + 101 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 231 + 232 @@ -6550,7 +6562,7 @@ 股息收益率 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 198 + 199 @@ -6606,7 +6618,7 @@ 删除活动 libs/ui/src/lib/activities-table/activities-table.component.html - 92 + 105 @@ -6630,7 +6642,7 @@ Jump to a page... libs/ui/src/lib/assistant/assistant.component.ts - 449 + 450 @@ -6686,7 +6698,7 @@ 包含在 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 399 + 400 @@ -6922,7 +6934,7 @@ 查看持仓 libs/ui/src/lib/activities-table/activities-table.component.html - 473 + 487 @@ -6978,11 +6990,11 @@ 取消 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 162 + 163 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 634 + 635 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7034,7 +7046,7 @@ 关闭 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 636 + 637 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7126,7 +7138,7 @@ 含货币影响的涨跌 涨跌 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 63 + 64 @@ -7142,7 +7154,7 @@ 含货币影响的表现 表现 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 83 + 84 @@ -7288,6 +7300,10 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 270 + + libs/ui/src/lib/activities-table/activities-table.component.html + 101 + cannot be self-hosted @@ -7608,7 +7624,7 @@ 保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 645 + 646 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7740,7 +7756,7 @@ 默认市场价格 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 519 + 520 @@ -7748,7 +7764,7 @@ 模式 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 556 + 557 @@ -7764,7 +7780,7 @@ 选择器 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 572 + 573 @@ -7772,7 +7788,7 @@ HTTP 请求标头 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 532 + 533 @@ -8017,7 +8033,7 @@ 应用 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 155 @@ -8108,6 +8124,18 @@ 142 + + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 102 + + Log out 登出 @@ -8577,7 +8605,7 @@ 管理资产概况 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 478 + 479 @@ -8605,7 +8633,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 101 + 102 From 0e42a62e9207e458b3db84d2606b26f18f41823b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 09:32:10 +0200 Subject: [PATCH 34/86] Task/improve color of checkboxes in type filter of activities table component (#7493) Improve color of checkboxes --- apps/client/src/styles/theme.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/client/src/styles/theme.scss b/apps/client/src/styles/theme.scss index 75ecc210d..3f8125011 100644 --- a/apps/client/src/styles/theme.scss +++ b/apps/client/src/styles/theme.scss @@ -364,6 +364,12 @@ $gf-typography: ( ) ); + @include mat.pseudo-checkbox-overrides( + ( + full-selected-icon-color: var(--gf-theme-primary-500) + ) + ); + @include mat.slide-toggle-overrides( ( selected-focus-handle-color: var(--gf-theme-primary-500), From c383eade6f193c8c9d13e1fbab04b168f5d75567 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 09:32:45 +0200 Subject: [PATCH 35/86] Task/improve language localization for DE (20260801) (#7497) * Update translations * Update changelog --- CHANGELOG.md | 6 ++++++ apps/client/src/locales/messages.de.xlf | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fe881b94..952ea923b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Improved the language localization for German (`de`) + ## 3.38.0 - 2026-07-31 ### Added diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 2765b0b4c..b2800165a 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -3051,7 +3051,7 @@ Export - Export + exportieren libs/ui/src/lib/activities-table/activities-table.component.html 68 @@ -5287,7 +5287,7 @@ Do you really want to delete these activities? - Do you really want to delete these activities? + Möchtest du diese Aktivitäten wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts 334 @@ -8125,7 +8125,7 @@ {VAR_PLURAL, plural, =1 {Activity} other {Activities}} - {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Aktivität} other {Aktivitäten}} libs/ui/src/lib/activities-table/activities-table.component.html 69 From caa9bef697fd04abdf4e9b0cbac277ed17d5fb69 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 09:45:18 +0200 Subject: [PATCH 36/86] Task/upgrade prisma to version 7.9.1 (#7498) * Update prisma to version 7.9.1 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 592 +++++++++++++++++++++++++++++++++++----------- package.json | 8 +- 3 files changed, 465 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 952ea923b..0512ad5bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the language localization for German (`de`) +- Upgraded `prisma` from version `7.8.0` to `7.9.1` ## 3.38.0 - 2026-07-31 diff --git a/package-lock.json b/package-lock.json index 04a7da5a3..1e49fb135 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,8 +43,8 @@ "@nestjs/serve-static": "5.0.5", "@nestjs/throttler": "6.5.0", "@openrouter/ai-sdk-provider": "3.0.0", - "@prisma/adapter-pg": "7.8.0", - "@prisma/client": "7.8.0", + "@prisma/adapter-pg": "7.9.1", + "@prisma/client": "7.9.1", "@simplewebauthn/browser": "13.3.0", "@simplewebauthn/server": "13.3.1", "ai": "7.0.37", @@ -127,7 +127,7 @@ "@nx/storybook": "23.0.2", "@nx/web": "23.0.2", "@nx/workspace": "23.0.2", - "@prisma/config": "7.8.0", + "@prisma/config": "7.9.1", "@schematics/angular": "21.2.6", "@storybook/addon-docs": "10.1.10", "@storybook/addon-themes": "10.1.10", @@ -157,7 +157,7 @@ "nx": "23.0.2", "prettier": "3.9.6", "prettier-plugin-organize-attributes": "1.0.0", - "prisma": "7.8.0", + "prisma": "7.9.1", "react": "18.2.0", "react-dom": "18.2.0", "replace-in-file": "8.4.0", @@ -3908,33 +3908,33 @@ } }, "node_modules/@electric-sql/pglite": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz", - "integrity": "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.3.tgz", + "integrity": "sha512-ichuWTgtd4mOM1G4SpyGJa5trT03lWbMypDV0fUXUCXg5hiHqVAz/bZyV68NqmkLB7WcYmj1RMJVSp8HV/v/ZQ==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@electric-sql/pglite-socket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.1.tgz", - "integrity": "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.3.tgz", + "integrity": "sha512-LAciWM0M1dCL8hlsxu2venbVZcdxema0BtDfpWYVqr+Y468UADw0pFWidhKw1M8sfJ8rdLT71tjMmnirf/IZRQ==", "devOptional": true, "license": "Apache-2.0", "bin": { "pglite-server": "dist/scripts/server.js" }, "peerDependencies": { - "@electric-sql/pglite": "0.4.1" + "@electric-sql/pglite": "0.4.3" } }, "node_modules/@electric-sql/pglite-tools": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.1.tgz", - "integrity": "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.3.tgz", + "integrity": "sha512-AlzLJTRJ8+UFgK8CmxIpyIpJ0+YaFw02IiOSdYrqxwPXdSyeIShz8aa9Tq+tYFXdPwcaMp/Fc80mQZ1dkOQ/wg==", "devOptional": true, "license": "Apache-2.0", "peerDependencies": { - "@electric-sql/pglite": "0.4.1" + "@electric-sql/pglite": "0.4.3" } }, "node_modules/@emnapi/core": { @@ -10041,24 +10041,24 @@ } }, "node_modules/@prisma/adapter-pg": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.8.0.tgz", - "integrity": "sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.9.1.tgz", + "integrity": "sha512-Ho2RK1KanQxLNSC0sR5bpiiVep10sWPLXCcxK+KXfI/Q69TMRbiafSvLPv3V9snimX72rMCqGlyJ4sBO4lKTAw==", "license": "Apache-2.0", "dependencies": { - "@prisma/driver-adapter-utils": "7.8.0", + "@prisma/driver-adapter-utils": "7.9.1", "@types/pg": "^8.16.0", "pg": "^8.16.3", "postgres-array": "3.0.4" } }, "node_modules/@prisma/client": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.8.0.tgz", - "integrity": "sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.9.1.tgz", + "integrity": "sha512-+xgrh2EhJVF79wC0yX5G4PI1Rdcm7Qn/nekNQ+t/O153wtNggruHal+fXHSa0QE+Tp/Cw5wvxeCEhZZ59xGm8Q==", "license": "Apache-2.0", "dependencies": { - "@prisma/client-runtime-utils": "7.8.0" + "@prisma/client-runtime-utils": "7.9.1" }, "engines": { "node": "^20.19 || ^22.12 || >=24.0" @@ -10077,15 +10077,15 @@ } }, "node_modules/@prisma/client-runtime-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.8.0.tgz", - "integrity": "sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.9.1.tgz", + "integrity": "sha512-mVIBGYdO5CFmK0HvjxrtfIyQQcPdb88pSCeVQriVQPVZyDovIWblpHfOgcS8QO187j3QF0ePArH8qPhp0AU2vg==", "license": "Apache-2.0" }, "node_modules/@prisma/config": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.8.0.tgz", - "integrity": "sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.9.1.tgz", + "integrity": "sha512-4znKhxTmXmuPye9Z6pbIyYb5VZlkZ05qG1L6Dr4g+7oTwc6V50Bs9XirFBDdjWt+H/AabMn9aUnxBcvj8z05aA==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -10096,97 +10096,95 @@ } }, "node_modules/@prisma/debug": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.8.0.tgz", - "integrity": "sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.9.1.tgz", + "integrity": "sha512-/cpVZ4itxtcgB8GHBvZtcmuEjq+lWsLrRJxFMbwZrT1RIdtuKmUm7PPGo/wzfbYpBrk+9WmmBE8CHJw2rybKDQ==", "license": "Apache-2.0" }, "node_modules/@prisma/dev": { - "version": "0.24.3", - "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.3.tgz", - "integrity": "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==", + "version": "0.24.17", + "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.17.tgz", + "integrity": "sha512-UvdZzmpFwknnfreh6Jije84ekkYGPYEJhXG1tFzCsCfQyzJifrOo38eZc0qajzvaC6OLUOrN9ML5XfCnEZL9DA==", "devOptional": true, "license": "ISC", "dependencies": { - "@electric-sql/pglite": "0.4.1", - "@electric-sql/pglite-socket": "0.1.1", - "@electric-sql/pglite-tools": "0.3.1", - "@hono/node-server": "1.19.11", + "@electric-sql/pglite": "0.4.3", + "@electric-sql/pglite-socket": "0.1.3", + "@electric-sql/pglite-tools": "0.3.3", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", - "@prisma/streams-local": "0.1.2", + "@prisma/streams-local": "0.1.11", + "find-my-way": "9.7.0", "foreground-child": "3.3.1", "get-port-please": "3.2.0", - "hono": "^4.12.8", - "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", "remeda": "2.33.4", "std-env": "3.10.0", - "valibot": "1.2.0", + "valibot": "1.4.2", "zeptomatch": "2.1.0" } }, "node_modules/@prisma/driver-adapter-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.8.0.tgz", - "integrity": "sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.9.1.tgz", + "integrity": "sha512-vmHehG7nn/heW32DXXpp13DxxAxVVe6n250oEt3dOL2E/4bt3olktKZN0mzSuxMMronyMSkbeW2uCOn3F4g8RQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.8.0" + "@prisma/debug": "7.9.1" } }, "node_modules/@prisma/engines": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.8.0.tgz", - "integrity": "sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.9.1.tgz", + "integrity": "sha512-UprXSMNXx2NF5ow4pqaQtE8OuBz6K78B0wc0tn2L28G5r933iWp1DR9Do2qWrsNvvFIP3x6mpEWnQtckMO0Uhg==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.8.0", - "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", - "@prisma/fetch-engine": "7.8.0", - "@prisma/get-platform": "7.8.0" + "@prisma/debug": "7.9.1", + "@prisma/engines-version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", + "@prisma/fetch-engine": "7.9.1", + "@prisma/get-platform": "7.9.1" } }, "node_modules/@prisma/engines-version": { - "version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a.tgz", - "integrity": "sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==", + "version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad.tgz", + "integrity": "sha512-2BsPPFksz3CQUXG6af3rVCtJKg6+JJGJTtfgu2fU8DdXhOfkBjulCq8mwybCd6ge0/jhZq2kOtLAbmUDMyI1nA==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz", - "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.9.1.tgz", + "integrity": "sha512-PK8R60YZRQvYxBrGG9i7l2/rFyzy+2MuI1dKtmtrCqPH8YpiJx/MfiC7LRzX5786rZDEv7BngcjfIJW4/9ADuw==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.8.0" + "@prisma/debug": "7.9.1" } }, "node_modules/@prisma/fetch-engine": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.8.0.tgz", - "integrity": "sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.9.1.tgz", + "integrity": "sha512-9DwxrNTeT25Orbu9CWh0CZvVlyY1lmscpbaeLZcOnuR7zcuFrt91YSmmOfIm7zJ08YOZ6mVzURKwLoMwEBcK8w==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.8.0", - "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", - "@prisma/get-platform": "7.8.0" + "@prisma/debug": "7.9.1", + "@prisma/engines-version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", + "@prisma/get-platform": "7.9.1" } }, "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz", - "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.9.1.tgz", + "integrity": "sha512-PK8R60YZRQvYxBrGG9i7l2/rFyzy+2MuI1dKtmtrCqPH8YpiJx/MfiC7LRzX5786rZDEv7BngcjfIJW4/9ADuw==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "7.8.0" + "@prisma/debug": "7.9.1" } }, "node_modules/@prisma/get-platform": { @@ -10214,9 +10212,9 @@ "license": "Apache-2.0" }, "node_modules/@prisma/streams-local": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.2.tgz", - "integrity": "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==", + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.11.tgz", + "integrity": "sha512-0TcebL559MByKqTJ+SsrFIEg228iw8UCVRFckzgfRSiJqczhs+MuAgWOF9lnOIV/IVqvu+KMnFTH0eDeTQMpUg==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -10226,7 +10224,7 @@ "proper-lockfile": "^4.1.2" }, "engines": { - "bun": ">=1.3.6", + "bun": ">=1.2.0", "node": ">=22.0.0" } }, @@ -10244,14 +10242,23 @@ } }, "node_modules/@prisma/studio-core": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.27.3.tgz", - "integrity": "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.33.0.tgz", + "integrity": "sha512-V2fX/nKEymNTrHXwfP26PGjoLStO35Ogu+ex7CFJbLrMYEcZxxZpiSNOs7px23Hk5mzLWvM5RsqG6Ka+rha+wg==", "devOptional": true, "license": "Apache-2.0", "dependencies": { "@radix-ui/react-toggle": "1.1.10", - "chart.js": "4.5.1" + "@visx/curve": "4.0.1-alpha.0", + "@visx/event": "4.0.1-alpha.0", + "@visx/grid": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/responsive": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/shape": "4.0.1-alpha.0", + "d3-array": "3.2.4", + "d3-shape": "3.2.0", + "elkjs": "0.11.1" }, "engines": { "node": "^20.19 || ^22.12 || >=24.0", @@ -12501,9 +12508,8 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "devOptional": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@types/geojson": "*" } @@ -12531,9 +12537,8 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT", - "optional": true, - "peer": true + "devOptional": true, + "license": "MIT" }, "node_modules/@types/d3-polygon": { "version": "3.0.2", @@ -12756,9 +12761,8 @@ "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT", - "optional": true, - "peer": true + "devOptional": true, + "license": "MIT" }, "node_modules/@types/google-spreadsheet": { "version": "3.1.5", @@ -12902,7 +12906,7 @@ "version": "4.17.24", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/luxon": { @@ -13056,7 +13060,6 @@ "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -14168,6 +14171,265 @@ "node": ">= 20" } }, + "node_modules/@visx/curve": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-4.0.1-alpha.0.tgz", + "integrity": "sha512-jRu61Uz274pV1zyioXmboyrLutYbnKsgjj4njSGCnhdXj5GkZvZbg+ThDb6oOzoAnJOBRLz4rzPlWvNJOzuVMg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@visx/vendor": "4.0.0-alpha.0" + } + }, + "node_modules/@visx/event": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/event/-/event-4.0.1-alpha.0.tgz", + "integrity": "sha512-EQqCMSv/s8NbFjo+hz3FKsvvYfP+2QslsFJ/24/O5l/W+7UC6J6aAvO0ujVwrTwdYbuQ+vhxKi1xdPdKR/qj1g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/point": "4.0.1-alpha.0" + } + }, + "node_modules/@visx/grid": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/grid/-/grid-4.0.1-alpha.0.tgz", + "integrity": "sha512-rycutGmTHO+znNdPumheWMglm7YfpffvRwUkVy5zy4WoORIuKTMkDxwnOzHG2xMxU3EE/YCd37xFV5AxA30yeg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/curve": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/point": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/shape": "4.0.1-alpha.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/group": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/group/-/group-4.0.1-alpha.0.tgz", + "integrity": "sha512-V19l7iQ7jccBv8kao/EByuI6o4xtxzzLV9nqVI1hRvmdzTVsuLpqlwzYCZUXJaTVvUWf8s4D2SQFjGkj/Nw+0w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/react": "*", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/point": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/point/-/point-4.0.1-alpha.0.tgz", + "integrity": "sha512-ijTfr/Nx09f03vIj9nyTr3z4Xth4Y75427UaogJh6dnIRLMEFHQOwNu791sbfiNj0a+ZXuaE32h0vKrFe4/8Qg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/responsive": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-4.0.1-alpha.0.tgz", + "integrity": "sha512-o+1zGywQZY0+yOx3Iw87wc4bbPJRr/HnIukTwfOz4UVyj9pB1OQNVHB7OORO1+LBHJceWpB31co/ZV9KHncKrA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.17.13", + "@types/react": "*", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/scale": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-4.0.1-alpha.0.tgz", + "integrity": "sha512-nzjeE87vFSAXGWFiiNfBpNLAf0Q8Qmf6syvKLjqNi4kGZkdhbUll3E/59YsgWXmjM8+llPLWzGsP+JPvo5eq1A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@visx/vendor": "4.0.0-alpha.0" + } + }, + "node_modules/@visx/shape": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-4.0.1-alpha.0.tgz", + "integrity": "sha512-62QeiVNmPlterQGwhkEDcbq7M0MqY0lBsK5QKXtM9ZoPZWkuGV3aykA3+Xu20B2FAvyJq4LqJzBc7Sxr+EAdbA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.17.13", + "@types/react": "*", + "@visx/curve": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/vendor": "4.0.0-alpha.0", + "classnames": "^2.3.1", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/vendor": { + "version": "4.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/vendor/-/vendor-4.0.0-alpha.0.tgz", + "integrity": "sha512-6I+MuqXBcv9jnlcVowHoHKSdk9gXTWkHLKyqBwRWg7LY6A3Ei8SHfubpqGV5rBUSppxMq2RszPJUS6w+H0YgmQ==", + "devOptional": true, + "license": "MIT and ISC", + "dependencies": { + "@types/d3-array": "3.0.3", + "@types/d3-color": "3.1.0", + "@types/d3-delaunay": "6.0.1", + "@types/d3-format": "3.0.1", + "@types/d3-geo": "3.1.0", + "@types/d3-interpolate": "3.0.1", + "@types/d3-path": "3.1.1", + "@types/d3-scale": "4.0.2", + "@types/d3-shape": "3.1.7", + "@types/d3-time": "3.0.0", + "@types/d3-time-format": "2.1.0", + "d3-array": "3.2.1", + "d3-color": "3.1.0", + "d3-delaunay": "6.0.2", + "d3-format": "3.1.0", + "d3-geo": "3.1.0", + "d3-interpolate": "3.0.1", + "d3-path": "3.1.0", + "d3-scale": "4.0.2", + "d3-shape": "3.2.0", + "d3-time": "3.1.0", + "d3-time-format": "4.1.0", + "internmap": "2.0.3" + } + }, + "node_modules/@visx/vendor/node_modules/@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@visx/vendor/node_modules/@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@visx/vendor/node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@visx/vendor/node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/@types/d3-time-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@visx/vendor/node_modules/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@visx/vendor/node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@visx/vendor/node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@visx/vendor/node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@vitejs/plugin-basic-ssl": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", @@ -15462,9 +15724,9 @@ } }, "node_modules/better-result": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.8.2.tgz", - "integrity": "sha512-YOf0VSj5nUPI27doTtXF+BBnsiRq3qY7avHqfIWnppxTLGyvkLq1QV2RTxkwoZwJ60ywLfZ0raFF4J/G886i7A==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.10.0.tgz", + "integrity": "sha512-oQhh0y1qo2/ZKdAAEvHZAqKKiHOFU5k/bW96fE2ScgQOVkJRiHwB+nOS1SgFsYqRlxMDWvefXi9Q3px7QvgNDw==", "devOptional": true, "license": "MIT" }, @@ -16392,6 +16654,13 @@ "validator": "^13.15.22" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "devOptional": true, + "license": "MIT" + }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -18049,8 +18318,7 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "devOptional": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/cytoscape": { "version": "3.33.2", @@ -18157,9 +18425,8 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "internmap": "1 - 2" }, @@ -18214,9 +18481,8 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "engines": { "node": ">=12" } @@ -18372,9 +18638,8 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "engines": { "node": ">=12" } @@ -18408,9 +18673,8 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "d3-color": "1 - 3" }, @@ -18422,9 +18686,8 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "engines": { "node": ">=12" } @@ -18516,9 +18779,8 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -18560,9 +18822,8 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "d3-path": "^3.1.0" }, @@ -18574,9 +18835,8 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "d3-array": "2 - 3" }, @@ -18588,9 +18848,8 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "d3-time": "1 - 3" }, @@ -18943,9 +19202,8 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "dependencies": { "robust-predicates": "^3.0.2" } @@ -19286,6 +19544,13 @@ "integrity": "sha512-mgjZAz7Jyx1SRCwEpy9wefDS7GvNPazLthHg8eQMJ76wBdGQQDW33TCrUTvQ4wzpmOrv2zrFoD3oNufMdyMpog==", "license": "ISC" }, + "node_modules/elkjs": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.11.1.tgz", + "integrity": "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==", + "devOptional": true, + "license": "EPL-2.0" + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -20460,6 +20725,13 @@ ], "license": "MIT" }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "devOptional": true, + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -20510,6 +20782,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, "node_modules/fast-redact": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", @@ -20898,6 +21180,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-my-way": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.7.0.tgz", + "integrity": "sha512-f2JHn75x2JlwUwLenZypgczR7YWMb/uO9BvUXtus+JMgkbIkLADd38cI4EiV+OQqrGo1Zlq6V8wnqMJ8e62wUQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^5.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -21768,9 +22065,9 @@ "license": "ISC" }, "node_modules/grammex": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.12.tgz", - "integrity": "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==", + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.13.tgz", + "integrity": "sha512-LnPnhOBLEJEVKS8WFDVaA397L9Kq55Q9oSITJiVLHVdhAclfUkWzQv74KhvZHKL2Q09Pb1XdsrOsZ4LfTFFTEg==", "devOptional": true, "license": "MIT" }, @@ -22645,9 +22942,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "devOptional": true, "license": "ISC", - "optional": true, - "peer": true, "engines": { "node": ">=12" } @@ -29188,17 +29484,17 @@ } }, "node_modules/prisma": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.8.0.tgz", - "integrity": "sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.9.1.tgz", + "integrity": "sha512-aPqePoZIqwlAchbgbFDO/wHqGB+7H1nj9gaM+OsL9h77S5S3TnLd9BgD3LnoeDikULo7cl2HSUrEyQ55Z7DYbg==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/config": "7.8.0", - "@prisma/dev": "0.24.3", - "@prisma/engines": "7.8.0", - "@prisma/studio-core": "0.27.3", + "@prisma/config": "7.9.1", + "@prisma/dev": "0.24.17", + "@prisma/engines": "7.9.1", + "@prisma/studio-core": "0.33.0", "mysql2": "3.15.3", "postgres": "3.4.7" }, @@ -30152,6 +30448,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ret": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -30183,9 +30489,8 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", - "license": "Unlicense", - "optional": true, - "peer": true + "devOptional": true, + "license": "Unlicense" }, "node_modules/rolldown": { "version": "1.0.0-rc.4", @@ -30532,6 +30837,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-regex2": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz", + "integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ret": "~0.5.0" + }, + "bin": { + "safe-regex2": "bin/safe-regex2.js" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -34374,9 +34702,9 @@ "license": "MIT" }, "node_modules/valibot": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", - "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.2.tgz", + "integrity": "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==", "devOptional": true, "license": "MIT", "peerDependencies": { diff --git a/package.json b/package.json index c2bc56d4a..194ee3ce3 100644 --- a/package.json +++ b/package.json @@ -87,8 +87,8 @@ "@nestjs/serve-static": "5.0.5", "@nestjs/throttler": "6.5.0", "@openrouter/ai-sdk-provider": "3.0.0", - "@prisma/adapter-pg": "7.8.0", - "@prisma/client": "7.8.0", + "@prisma/adapter-pg": "7.9.1", + "@prisma/client": "7.9.1", "@simplewebauthn/browser": "13.3.0", "@simplewebauthn/server": "13.3.1", "ai": "7.0.37", @@ -171,7 +171,7 @@ "@nx/storybook": "23.0.2", "@nx/web": "23.0.2", "@nx/workspace": "23.0.2", - "@prisma/config": "7.8.0", + "@prisma/config": "7.9.1", "@schematics/angular": "21.2.6", "@storybook/addon-docs": "10.1.10", "@storybook/addon-themes": "10.1.10", @@ -201,7 +201,7 @@ "nx": "23.0.2", "prettier": "3.9.6", "prettier-plugin-organize-attributes": "1.0.0", - "prisma": "7.8.0", + "prisma": "7.9.1", "react": "18.2.0", "react-dom": "18.2.0", "replace-in-file": "8.4.0", From 179be2f564c3a25691f6b1a8597e9ee0f820d7f5 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 10:21:28 +0200 Subject: [PATCH 37/86] Task/add portfolio summary tests (#7458) Add portfolio summary tests --- .../app/portfolio/portfolio.service.spec.ts | 86 ++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index d85258f7e..699e79e0d 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -1,6 +1,7 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; +import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator'; import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { UserService } from '@ghostfolio/api/app/user/user.service'; @@ -11,7 +12,10 @@ import { ImpersonationService } from '@ghostfolio/api/services/impersonation/imp import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { parseDate } from '@ghostfolio/common/helper'; -import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; +import { + AssetProfileIdentifier, + PortfolioSummary +} from '@ghostfolio/common/interfaces'; import { Account, DataSource } from '@prisma/client'; import { Big } from 'big.js'; @@ -338,6 +342,86 @@ describe('PortfolioService', () => { }); }); + describe('getSummary', () => { + const getSummary = (args: object) => { + return ( + portfolioService as unknown as { + getSummary: (aArgs: object) => Promise; + } + ).getSummary(args); + }; + + function createPortfolioCalculator() { + return { + getDividendInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), + getFeesInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), + getInterestInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), + getLiabilitiesInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), + getSnapshot: jest.fn().mockResolvedValue({ + currentValueInBaseCurrency: new Big(3000), + totalCashInBaseCurrency: new Big(1000), + totalInvestment: new Big(2000), + totalInvestmentWithCurrencyEffect: new Big(2000) + }), + getStartDate: jest.fn().mockReturnValue(parseDate('2024-01-01')) + } as unknown as PortfolioCalculator; + } + + beforeEach(() => { + jest + .spyOn(activitiesService, 'getActivities') + .mockResolvedValue({ activities: [], count: 0 }); + + jest + .spyOn(impersonationService, 'validateImpersonationId') + .mockResolvedValue(null); + + jest.spyOn(portfolioService, 'getPerformance').mockResolvedValue({ + performance: { + currentValueInBaseCurrency: 3000, + netPerformance: 500, + netPerformancePercentage: 0.2, + netPerformancePercentageWithCurrencyEffect: 0.2, + netPerformanceWithCurrencyEffect: 500 + } + } as Awaited>); + + jest.spyOn(userService, 'user').mockResolvedValue({ + id: userDummyData.id, + settings: { + settings: { + baseCurrency: 'CHF' + } + } + } as unknown as Awaited>); + }); + + it('should derive the cash and net worth from the account balance when there are no excluded accounts, no emergency fund and no liabilities', async () => { + jest.spyOn(accountService, 'getCashDetails').mockResolvedValue({ + accounts: [], + balanceInBaseCurrency: 1000 + }); + + const portfolioCalculator = createPortfolioCalculator(); + + const summary = await getSummary({ + portfolioCalculator, + balanceInBaseCurrency: 1000, + emergencyFundHoldingsValueInBaseCurrency: 0, + filteredValueInBaseCurrency: new Big(3000), + impersonationId: undefined, + userCurrency: 'CHF', + userId: userDummyData.id + }); + + expect(summary.cash).toBe(1000); + expect(summary.emergencyFund.total).toBe(0); + expect(summary.excludedAccountsAndActivities).toBe(0); + expect(summary.totalAssetsInBaseCurrency).toBe(3000); + expect(summary.totalValueInBaseCurrency).toBe(3000); + }); + }); + describe('getValueOfAccountsAndPlatforms', () => { const getValueOfAccountsAndPlatforms = (args: object) => { return ( From 5f47a2f2a77d7ca0793ca68917b6ed0390cec9c2 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 10:26:28 +0200 Subject: [PATCH 38/86] Task/improve export functionality (#7499) * Improve export functionality * Update changelog --- CHANGELOG.md | 5 ++++ apps/api/src/app/export/export.service.ts | 9 +++++++- .../user-account-settings.component.ts | 4 ---- .../activities/activities-page.component.ts | 6 +---- libs/ui/src/lib/services/data.service.ts | 23 +++++++++++++++---- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0512ad5bf..c242cac5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Harmonized the data format of the export functionality - Improved the language localization for German (`de`) - Upgraded `prisma` from version `7.8.0` to `7.9.1` +### Fixed + +- Fixed the export functionality to only include the accounts of the exported activities if a filter is applied + ## 3.38.0 - 2026-07-31 ### Added diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 6e920553b..ec9b89a81 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -73,6 +73,13 @@ export class ExportService { }; } + const isFilteredExport = + activityIds?.length > 0 || + activityTypes?.length > 0 || + filters?.length > 0 || + !!endDate || + !!startDate; + const accounts = ( await this.accountService.accounts({ where, @@ -87,7 +94,7 @@ export class ExportService { }) ) .filter(({ id }) => { - return activityIds?.length > 0 + return isFilteredExport ? activities.some(({ accountId }) => { return accountId === id; }) diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index a556a68d6..0a049a7ae 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -266,10 +266,6 @@ export class GfUserAccountSettingsComponent implements OnInit { .fetchExport() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { - for (const activity of data.activities) { - delete (activity as Omit & { id?: string }).id; - } - downloadAsFile({ content: data, fileName: `ghostfolio-export-${format( diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts index 87da2fb84..0ff4168ac 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts @@ -177,10 +177,6 @@ export class GfActivitiesPageComponent implements OnInit { .fetchExport(fetchExportParams) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { - for (const activity of data.activities) { - delete (activity as Omit & { id?: string }).id; - } - downloadAsFile({ content: data, fileName: `ghostfolio-export-${format( @@ -194,7 +190,7 @@ export class GfActivitiesPageComponent implements OnInit { protected onExportDrafts(activityIds?: string[]) { this.dataService - .fetchExport({ activityIds }) + .fetchExport({ activityIds, withActivityIds: true }) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { downloadAsFile({ diff --git a/libs/ui/src/lib/services/data.service.ts b/libs/ui/src/lib/services/data.service.ts index 870719702..bc1512550 100644 --- a/libs/ui/src/lib/services/data.service.ts +++ b/libs/ui/src/lib/services/data.service.ts @@ -476,12 +476,14 @@ export class DataService { activityIds, activityTypes, filters, - range + range, + withActivityIds = false }: { activityIds?: string[]; activityTypes?: string[]; filters?: Filter[]; range?: DateRange; + withActivityIds?: boolean; } = {}) { let params = this.buildFiltersAsQueryParams({ filters }); @@ -497,9 +499,22 @@ export class DataService { params = params.append('range', range); } - return this.http.get('/api/v1/export', { - params - }); + return this.http + .get('/api/v1/export', { + params + }) + .pipe( + map((exportResponse) => { + if (!withActivityIds) { + for (const activity of exportResponse.activities) { + delete (activity as Omit & { id?: string }) + .id; + } + } + + return exportResponse; + }) + ); } public fetchHoldingDetail({ From 5092316609b2577ffa2d6bfaaeeeb9eacddf65fa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 10:40:18 +0200 Subject: [PATCH 39/86] Bugfix/scroll behavior of page content behind open dialog (#7500) * Fix scroll behavior of page content behind open dialog * Update changelog --- CHANGELOG.md | 1 + apps/client/src/index.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c242cac5a..8c47efb2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed the scroll behavior of the page content behind an open dialog - Fixed the export functionality to only include the accounts of the exported activities if a filter is applied ## 3.38.0 - 2026-07-31 diff --git a/apps/client/src/index.html b/apps/client/src/index.html index 61953bca8..105e7bcae 100644 --- a/apps/client/src/index.html +++ b/apps/client/src/index.html @@ -1,5 +1,5 @@ - + Ghostfolio From 5e9ac0169e912d1480ca9a5f6db06b3f52fee8fb Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 10:41:01 +0200 Subject: [PATCH 40/86] Task/remove deprecated firstOrderDate from portfolio performance endpoint response (#7483) * Remove deprecated firstOrderDate * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/portfolio/portfolio.service.ts | 2 -- .../responses/portfolio-performance-response.interface.ts | 6 ------ 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c47efb2e..b80a682c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Harmonized the data format of the export functionality +- Removed the deprecated `firstOrderDate` attribute from the `GET api/v2/portfolio/performance` endpoint response - Improved the language localization for German (`de`) - Upgraded `prisma` from version `7.8.0` to `7.9.1` diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d1aff3811..0a69cf32d 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1035,7 +1035,6 @@ export class PortfolioService { return { chart: [], dateOfFirstActivity: undefined, - firstOrderDate: undefined, hasErrors: false, performance: { currentNetWorth: 0, @@ -1093,7 +1092,6 @@ export class PortfolioService { errors, hasErrors, dateOfFirstActivity: parseDate(historicalData[0]?.date), - firstOrderDate: parseDate(historicalData[0]?.date), performance: { netPerformance, netPerformanceWithCurrencyEffect, diff --git a/libs/common/src/lib/interfaces/responses/portfolio-performance-response.interface.ts b/libs/common/src/lib/interfaces/responses/portfolio-performance-response.interface.ts index 104302de3..8177bd533 100644 --- a/libs/common/src/lib/interfaces/responses/portfolio-performance-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/portfolio-performance-response.interface.ts @@ -5,11 +5,5 @@ import { ResponseError } from './errors.interface'; export interface PortfolioPerformanceResponse extends ResponseError { chart?: HistoricalDataItem[]; dateOfFirstActivity: Date; - - /** - * @deprecated Use `dateOfFirstActivity` instead - */ - firstOrderDate: Date; - performance: PortfolioPerformance; } From 263e064fd6b1c55cc547a071023f4dced6185037 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:27:47 +0200 Subject: [PATCH 41/86] Task/remove deprecated attribute isExcluded from account (#7253) * Remove deprecated attribute isExcluded from account * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/export/export.service.ts | 2 -- apps/api/src/app/import/import.service.ts | 21 +++++++++++++++++-- .../roai/portfolio-calculator-cash.spec.ts | 3 --- .../app/portfolio/portfolio.service.spec.ts | 3 --- apps/api/src/helper/account.helper.ts | 1 - .../pages/accounts/accounts-page.component.ts | 3 --- ...eate-or-update-account-dialog.component.ts | 4 ---- .../create-or-update-account-dialog.html | 5 ----- .../dtos/create-account-with-balances.dto.ts | 10 ++++++++- .../common/src/lib/dtos/create-account.dto.ts | 8 ------- .../common/src/lib/dtos/update-account.dto.ts | 8 ------- libs/common/src/lib/helper.ts | 6 +----- .../accounts-table.component.stories.ts | 3 --- .../activities-table.component.stories.ts | 5 ----- .../migration.sql | 21 +++++++++++++++++++ prisma/schema.prisma | 3 --- 17 files changed, 51 insertions(+), 56 deletions(-) create mode 100644 prisma/migrations/20260801103609_removed_is_excluded_from_account/migration.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index b80a682c4..72a0cc95f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Harmonized the data format of the export functionality - Removed the deprecated `firstOrderDate` attribute from the `GET api/v2/portfolio/performance` endpoint response +- Removed the deprecated `isExcluded` attribute of the account in favor of the _Exclude from Analysis_ tag including a data migration - Improved the language localization for German (`de`) - Upgraded `prisma` from version `7.8.0` to `7.9.1` diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index ec9b89a81..02ccb46b3 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -107,7 +107,6 @@ export class ExportService { comment, currency, id, - isExcluded, name, platform, platformId, @@ -125,7 +124,6 @@ export class ExportService { comment, currency, id, - isExcluded, name, platformId, tags: tags.map(({ id: tagId }) => { diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index b706baa8d..b8579b795 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -9,7 +9,10 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data/market-d import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; -import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; +import { + DATA_GATHERING_QUEUE_PRIORITY_HIGH, + TAG_ID_EXCLUDE_FROM_ANALYSIS +} from '@ghostfolio/common/config'; import { CreateAssetProfileDto, CreateOrderDto } from '@ghostfolio/common/dtos'; import { getAssetProfileIdentifier, @@ -272,7 +275,11 @@ export class ImportService { // If there is no account or if the account belongs to a different user then create a new account if (!accountWithSameId || accountWithSameId.userId !== user.id) { - const account = omit(accountWithBalances, ['balances', 'tags']); + const account = omit(accountWithBalances, [ + 'balances', + 'isExcluded', + 'tags' + ]); let oldAccountId: string; const platformId = account.platformId; @@ -292,6 +299,16 @@ export class ImportService { return existingTagIds.has(tagId); }); + // Map the legacy isExcluded attribute of old export files to + // the "Exclude from Analysis" tag + if ( + accountWithBalances.isExcluded && + existingTagIds.has(TAG_ID_EXCLUDE_FROM_ANALYSIS) && + !tagIds.includes(TAG_ID_EXCLUDE_FROM_ANALYSIS) + ) { + tagIds.push(TAG_ID_EXCLUDE_FROM_ANALYSIS); + } + let accountObject: Prisma.AccountCreateInput = { ...account, balances: { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index 1fc705b46..aaa2f63cf 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -186,7 +186,6 @@ describe('PortfolioCalculator', () => { createdAt: parseDate('2023-12-31'), currency: 'USD', id: accountId, - isExcluded: false, name: 'USD', platformId: null, updatedAt: parseDate('2023-12-31'), @@ -362,7 +361,6 @@ describe('PortfolioCalculator', () => { createdAt: parseDate('2023-12-31'), currency: 'CHF', id: accountId, - isExcluded: false, name: 'CHF', platformId: null, updatedAt: parseDate('2023-12-31'), @@ -494,7 +492,6 @@ describe('PortfolioCalculator', () => { createdAt: parseDate('2023-12-31'), currency: 'CHF', id: accountId, - isExcluded: false, name: 'CHF', platformId: null, updatedAt: parseDate('2023-12-31'), diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index 699e79e0d..97635553f 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -192,7 +192,6 @@ describe('PortfolioService', () => { createdAt: parseDate('2024-01-01'), currency: 'USD', id: randomUUID(), - isExcluded: false, name: 'USD', platformId: null, updatedAt: parseDate('2024-01-01'), @@ -226,7 +225,6 @@ describe('PortfolioService', () => { createdAt: parseDate('2024-01-01'), currency: 'USD', id: accountId, - isExcluded: false, name: 'USD', platformId: null, updatedAt: parseDate('2024-01-01'), @@ -438,7 +436,6 @@ describe('PortfolioService', () => { balance: 100, currency: 'USD', id: randomUUID(), - isExcluded: false, name: 'Account 1', platform: { name: 'Platform 1' }, platformId: randomUUID() diff --git a/apps/api/src/helper/account.helper.ts b/apps/api/src/helper/account.helper.ts index 8e7520d0a..da0762ba5 100644 --- a/apps/api/src/helper/account.helper.ts +++ b/apps/api/src/helper/account.helper.ts @@ -4,7 +4,6 @@ import { Prisma } from '@prisma/client'; import { endOfToday, isAfter } from 'date-fns'; export const WHERE_ACCOUNT_NOT_EXCLUDED: Prisma.AccountWhereInput = { - isExcluded: false, tags: { none: { tagId: TAG_ID_EXCLUDE_FROM_ANALYSIS diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index 1cf0e44a7..291a7f3f9 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -191,7 +191,6 @@ export class GfAccountsPageComponent implements OnInit { comment, currency, id, - isExcluded, name, platformId, tags @@ -206,7 +205,6 @@ export class GfAccountsPageComponent implements OnInit { comment, currency, id, - isExcluded, name, platformId, tags @@ -288,7 +286,6 @@ export class GfAccountsPageComponent implements OnInit { comment: null, currency: this.user?.settings?.baseCurrency ?? null, id: null, - isExcluded: false, name: null, platformId: null, tags: [] diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts index de0172eac..8b0536ebf 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts @@ -27,7 +27,6 @@ import { } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; -import { MatCheckboxModule } from '@angular/material/checkbox'; import { MAT_DIALOG_DATA, MatDialogModule, @@ -51,7 +50,6 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces'; GfTagsSelectorComponent, MatAutocompleteModule, MatButtonModule, - MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatInputModule, @@ -106,7 +104,6 @@ export class GfCreateOrUpdateAccountDialogComponent { balance: [this.data.account.balance, Validators.required], comment: [this.data.account.comment], currency: [this.data.account.currency, Validators.required], - isExcluded: [this.data.account.isExcluded], name: [this.data.account.name, Validators.required], platformId: [null, this.autocompleteObjectValidator()], tags: [ @@ -204,7 +201,6 @@ export class GfCreateOrUpdateAccountDialogComponent { comment: this.accountForm.get('comment')?.value ?? null, currency: this.accountForm.get('currency')?.value, id: this.accountForm.get('accountId')?.value, - isExcluded: this.accountForm.get('isExcluded')?.value, name: this.accountForm.get('name')?.value, platformId: this.accountForm.get('platformId')?.value?.id ?? null, tags: this.accountForm diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html index d5743313d..4e4c62b6f 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -92,11 +92,6 @@ [tagsAvailable]="tagsAvailable" />
-
- Exclude from Analysis -
@if (data.account.id) {
diff --git a/libs/common/src/lib/dtos/create-account-with-balances.dto.ts b/libs/common/src/lib/dtos/create-account-with-balances.dto.ts index 2d1d3ed2a..8fc6f78e4 100644 --- a/libs/common/src/lib/dtos/create-account-with-balances.dto.ts +++ b/libs/common/src/lib/dtos/create-account-with-balances.dto.ts @@ -1,6 +1,6 @@ import { AccountBalance } from '@ghostfolio/common/interfaces'; -import { IsArray, IsOptional } from 'class-validator'; +import { IsArray, IsBoolean, IsOptional } from 'class-validator'; import { CreateAccountDto } from './create-account.dto'; @@ -8,4 +8,12 @@ export class CreateAccountWithBalancesDto extends CreateAccountDto { @IsArray() @IsOptional() balances?: AccountBalance[]; + + /** + * @deprecated Accepted for backward compatibility with old export files + * and mapped to the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) + */ + @IsBoolean() + @IsOptional() + isExcluded?: boolean; } diff --git a/libs/common/src/lib/dtos/create-account.dto.ts b/libs/common/src/lib/dtos/create-account.dto.ts index b04193020..e4a0c64fe 100644 --- a/libs/common/src/lib/dtos/create-account.dto.ts +++ b/libs/common/src/lib/dtos/create-account.dto.ts @@ -4,7 +4,6 @@ import { Transform, TransformFnParams } from 'class-transformer'; import { ArrayUnique, IsArray, - IsBoolean, IsNumber, IsOptional, IsString, @@ -30,13 +29,6 @@ export class CreateAccountDto { @IsString() id?: string; - /** - * @deprecated Use the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) instead - */ - @IsBoolean() - @IsOptional() - isExcluded?: boolean; - @IsString() name: string; diff --git a/libs/common/src/lib/dtos/update-account.dto.ts b/libs/common/src/lib/dtos/update-account.dto.ts index 7a33da2df..a6a3e6ac6 100644 --- a/libs/common/src/lib/dtos/update-account.dto.ts +++ b/libs/common/src/lib/dtos/update-account.dto.ts @@ -4,7 +4,6 @@ import { Transform, TransformFnParams } from 'class-transformer'; import { ArrayUnique, IsArray, - IsBoolean, IsNumber, IsOptional, IsString, @@ -29,13 +28,6 @@ export class UpdateAccountDto { @IsString() id: string; - /** - * @deprecated Use the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) instead - */ - @IsBoolean() - @IsOptional() - isExcluded?: boolean; - @IsString() name: string; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 98f097b44..db1d3c2a2 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -456,12 +456,8 @@ export function interpolate(template: string, context: any) { }); } -export function isAccountExcluded(account: { - isExcluded: boolean; - tags?: { id: string }[]; -}) { +export function isAccountExcluded(account: { tags?: { id: string }[] }) { return ( - account.isExcluded || account.tags?.some(({ id }) => { return id === TAG_ID_EXCLUDE_FROM_ANALYSIS; }) === true diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts index 62a01164f..a38ca826c 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts @@ -24,7 +24,6 @@ const accounts = [ createdAt: new Date('2025-06-01T06:52:49.063Z'), currency: 'USD', id: '460d7401-ca43-4ed4-b08e-349f1822e9db', - isExcluded: false, name: 'Coinbase Account', platform: { id: '8dc24b88-bb92-4152-af25-fe6a31643e26', @@ -46,7 +45,6 @@ const accounts = [ createdAt: new Date('2025-06-01T06:48:53.055Z'), currency: 'USD', id: '6d773e31-0583-4c85-a247-e69870b4f1ee', - isExcluded: false, name: 'Private Banking Account', platform: { id: '43e8fcd1-5b79-4100-b678-d2229bd1660d', @@ -68,7 +66,6 @@ const accounts = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platform: { id: '9da3a8a7-4795-43e3-a6db-ccb914189737', diff --git a/libs/ui/src/lib/activities-table/activities-table.component.stories.ts b/libs/ui/src/lib/activities-table/activities-table.component.stories.ts index 057747cf1..0136545cf 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.stories.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.stories.ts @@ -44,7 +44,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -111,7 +110,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -178,7 +176,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -245,7 +242,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -312,7 +308,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), diff --git a/prisma/migrations/20260801103609_removed_is_excluded_from_account/migration.sql b/prisma/migrations/20260801103609_removed_is_excluded_from_account/migration.sql new file mode 100644 index 000000000..5fb01f5d2 --- /dev/null +++ b/prisma/migrations/20260801103609_removed_is_excluded_from_account/migration.sql @@ -0,0 +1,21 @@ +-- Create the "EXCLUDE_FROM_ANALYSIS" tag if it does not exist yet +INSERT INTO "Tag" ("id", "name") +VALUES ('f2e868af-8333-459f-b161-cbc6544c24bd', 'EXCLUDE_FROM_ANALYSIS') +ON CONFLICT DO NOTHING; + +-- Migrate accounts with "isExcluded" to the "EXCLUDE_FROM_ANALYSIS" tag +INSERT INTO "TagsOnAccounts" ("accountId", "tagId", "updatedAt", "userId") +SELECT + "id", + 'f2e868af-8333-459f-b161-cbc6544c24bd', + CURRENT_TIMESTAMP, + "userId" +FROM "Account" +WHERE "isExcluded" = true +ON CONFLICT DO NOTHING; + +-- DropIndex +DROP INDEX "Account_isExcluded_idx"; + +-- AlterTable +ALTER TABLE "Account" DROP COLUMN "isExcluded"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 733399506..faf7a9259 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -33,8 +33,6 @@ model Account { createdAt DateTime @default(now()) currency String? id String @default(uuid()) - /// @deprecated Use the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) instead - isExcluded Boolean @default(false) name String? platform Platform? @relation(fields: [platformId], references: [id]) platformId String? @@ -46,7 +44,6 @@ model Account { @@id([id, userId]) @@index([currency]) @@index([id]) - @@index([isExcluded]) @@index([name]) @@index([userId]) } From a64f7144fe0f17b82360e3aec92febb4eb27e47f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:31:58 +0200 Subject: [PATCH 42/86] Release 3.39.0 (#7503) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a0cc95f..b31046e8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 3.39.0 - 2026-08-01 ### Changed diff --git a/package-lock.json b/package-lock.json index 1e49fb135..9009b4f29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.38.0", + "version": "3.39.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.38.0", + "version": "3.39.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 194ee3ce3..ded794ce4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.38.0", + "version": "3.39.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 1822a09c6a97982a2eb045b3a00e117332f9991a Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 2 Aug 2026 02:40:26 +0700 Subject: [PATCH 43/86] Task/improve language localization for ZH (20260731) (#7490) * Update translations * Update changelog --- CHANGELOG.md | 6 + apps/client/src/locales/messages.zh.xlf | 152 ++++++++++++------------ 2 files changed, 82 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b31046e8c..cf5ab1a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Improved the language localization for Chinese (`zh`) + ## 3.39.0 - 2026-08-01 ### Changed diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index a70be75d6..7963e7767 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -433,7 +433,7 @@ Copy - Copy + 复制 libs/ui/src/lib/notifications/alert-dialog/alert-dialog.html 20 @@ -605,7 +605,7 @@ Paid - Paid + 付费 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 129 @@ -657,7 +657,7 @@ Unknown - Unknown + 未知 libs/ui/src/lib/i18n.ts 88 @@ -701,7 +701,7 @@ and is driven by the efforts of its contributors - 并且得益于其 贡献者 + 并且得益于其 贡献者 apps/client/src/app/pages/about/overview/about-overview-page.html 50 @@ -749,7 +749,7 @@ Find an account... - Find an account... + 查找账户... libs/ui/src/lib/assistant/assistant.component.ts 448 @@ -777,7 +777,7 @@ Watch the Ghostfol.io Trailer on YouTube - Watch the Ghostfol.io Trailer on YouTube + 在 YouTube 上观看 Ghostfol.io 预告片 apps/client/src/app/pages/landing/landing-page.html 19 @@ -813,7 +813,7 @@ Category - Category + 类别 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -837,7 +837,7 @@ An error occurred while converting the data source to . - An error occurred while converting the data source to . + 将数据源转换为 时发生错误。 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 482 @@ -885,7 +885,7 @@ Data Gathering Frequency - Data Gathering Frequency + 数据采集频率 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 468 @@ -921,7 +921,7 @@ Apply current market price - Apply current market price + 应用当前市场价格 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 238 @@ -929,7 +929,7 @@ Subscription History - Subscription History + 订阅历史 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 141 @@ -965,7 +965,7 @@ Healthcare - Healthcare + 医疗保健 libs/ui/src/lib/i18n.ts 97 @@ -1081,7 +1081,7 @@ Update Activity - Update Activity + 更新活动 libs/common/src/lib/routes/routes.ts 141 @@ -1089,7 +1089,7 @@ Technology - Technology + 科技 libs/ui/src/lib/i18n.ts 101 @@ -1105,7 +1105,7 @@ Total - Total + 总计 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 160 @@ -1161,7 +1161,7 @@ Industrials - Industrials + 工业 libs/ui/src/lib/i18n.ts 98 @@ -1197,7 +1197,7 @@ Consumer Cyclical - Consumer Cyclical + 非必需消费品 libs/ui/src/lib/i18n.ts 93 @@ -1705,7 +1705,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - 源代码完全可用,作为开源软件 (OSS),遵循AGPL-3.0许可证 + 源代码完全可用,作为开源软件 (OSS),遵循AGPL-3.0许可证 apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -1889,7 +1889,7 @@ Energy - Energy + 能源 libs/ui/src/lib/i18n.ts 95 @@ -2265,7 +2265,7 @@ Ghostfolio in Numbers: Monthly Active Users (MAU) - Ghostfolio in Numbers: Monthly Active Users (MAU) + Ghostfolio 数据:月活跃用户数 (MAU) apps/client/src/app/pages/landing/landing-page.html 63 @@ -2305,7 +2305,7 @@ The value has been copied to the clipboard - The value has been copied to the clipboard + 该值已复制到剪贴板 libs/ui/src/lib/notifications/alert-dialog/alert-dialog.component.ts 46 @@ -2357,7 +2357,7 @@ Consumer Defensive - Consumer Defensive + 必需消费品 libs/ui/src/lib/i18n.ts 94 @@ -2429,7 +2429,7 @@ Utilities - Utilities + 公用事业 libs/ui/src/lib/i18n.ts 102 @@ -2461,7 +2461,7 @@ Coupon - Coupon + 优惠券 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 134 @@ -2497,7 +2497,7 @@ Close Account - Close Account + 关闭账户 apps/client/src/app/components/user-account-settings/user-account-settings.html 337 @@ -2517,7 +2517,7 @@ Contributors to Ghostfolio - Contributors to Ghostfolio + Ghostfolio 贡献者 apps/client/src/app/pages/about/overview/about-overview-page.html 54 @@ -2561,7 +2561,7 @@ Investments - Investments + 投资 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 197 @@ -2853,7 +2853,7 @@ Financial Planning - Financial Planning + 财务规划 libs/ui/src/lib/i18n.ts 109 @@ -3121,7 +3121,7 @@ popular - popular + 热门 apps/client/src/app/components/admin-settings/admin-settings.component.html 79 @@ -3157,7 +3157,7 @@ Invalid API key - Invalid API key + 无效的 API 密钥 apps/client/src/app/components/admin-settings/admin-settings.component.html 112 @@ -3201,7 +3201,7 @@ For security reasons, please delete all activities and accounts first before your Ghostfolio account can be closed. - For security reasons, please delete all activities and accounts first before your Ghostfolio account can be closed. + 出于安全原因,在关闭您的 Ghostfolio 账户之前,请先删除所有活动和账户。 apps/client/src/app/components/user-account-settings/user-account-settings.html 348 @@ -3329,7 +3329,7 @@ Creation - Creation + 创建时间 apps/client/src/app/components/admin-overview/admin-overview.html 185 @@ -3373,7 +3373,7 @@ just now - just now + 刚刚 apps/client/src/app/components/admin-users/admin-users.component.ts 221 @@ -3561,7 +3561,7 @@ Basic Materials - Basic Materials + 基础材料 libs/ui/src/lib/i18n.ts 91 @@ -3705,7 +3705,7 @@ Oops! Could not delete the asset profiles. - Oops! Could not delete the asset profiles. + 哎呀!无法删除资产概况。 apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 52 @@ -3777,7 +3777,7 @@ Add Activity - Add Activity + 添加活动 libs/common/src/lib/routes/routes.ts 134 @@ -3801,7 +3801,7 @@ At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. - 在 Ghostfolio,透明度是我们价值观的核心。我们将源代码发布为开源软件(OSS)下AGPL-3.0许可证我们公开分享平台运营状态的汇总关键指标。 + 在 Ghostfolio,透明度是我们价值观的核心。我们将源代码发布为开源软件(OSS)下AGPL-3.0许可证我们公开分享平台运营状态的汇总关键指标。 apps/client/src/app/pages/open/open-page.html 7 @@ -3845,7 +3845,7 @@ Convert to - Convert to + 转换为 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 175 @@ -3897,7 +3897,7 @@ Available on - Available on + 适用于 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 130 @@ -4197,7 +4197,7 @@ Price - Price + 价格 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 176 @@ -4205,7 +4205,7 @@ Do you really want to convert this asset profile to ()? - Do you really want to convert this asset profile to ()? + 您确定要把此资产概况转换为 () 吗? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 723 @@ -4305,7 +4305,7 @@ Trial - Trial + 试用 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 133 @@ -4605,7 +4605,7 @@ Hourly - Hourly + 每小时 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 216 @@ -4717,7 +4717,7 @@ Expiration - Expiration + 到期时间 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 209 @@ -4970,7 +4970,7 @@ Coupon has been created - Coupon has been created + 优惠券 已创建 apps/client/src/app/components/admin-overview/admin-overview.component.ts 224 @@ -5022,7 +5022,7 @@ Upgrade to Ghostfolio Premium - Upgrade to Ghostfolio Premium + 升级至 Ghostfolio Premium libs/ui/src/lib/premium-indicator/premium-indicator.component.html 4 @@ -5110,7 +5110,7 @@ Stock Tracking - Stock Tracking + 股票追踪 libs/ui/src/lib/i18n.ts 112 @@ -5134,7 +5134,7 @@ Web - Web + 网页 libs/ui/src/lib/i18n.ts 121 @@ -5334,7 +5334,7 @@ Portfolio Filters - Portfolio Filters + 组合筛选器 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 63 @@ -5390,7 +5390,7 @@ {VAR_PLURAL, plural, =1 {Profile} other {Profiles}} - {VAR_PLURAL, plural, =1 {Profile} other {Profiles}} + {VAR_PLURAL, plural, =1 {个资产概况} other {个资产概况}} apps/client/src/app/components/admin-market-data/admin-market-data.html 275 @@ -5710,7 +5710,7 @@ Ghostfolio in Numbers: Pulls on Docker Hub - Ghostfolio in Numbers: Pulls on Docker Hub + Ghostfolio 数据:Docker Hub 下载量 apps/client/src/app/pages/landing/landing-page.html 101 @@ -6022,7 +6022,7 @@ Communication Services - Communication Services + 通信服务 libs/ui/src/lib/i18n.ts 92 @@ -6062,7 +6062,7 @@ Invested Capital - Invested Capital + 投入资本 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 174 @@ -6346,7 +6346,7 @@ Expires () - Expires () + 到期时间 () apps/client/src/app/components/admin-users/admin-users.html 34 @@ -6386,7 +6386,7 @@ Fetch market price - Fetch market price + 获取市场价格 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html 40 @@ -6479,7 +6479,7 @@ Find a holding... - Find a holding... + 查找持仓... libs/ui/src/lib/assistant/assistant.component.ts 449 @@ -6507,7 +6507,7 @@ Daily - Daily + 每天 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 212 @@ -6639,7 +6639,7 @@ Jump to a page... - Jump to a page... + 跳转到页面... libs/ui/src/lib/assistant/assistant.component.ts 450 @@ -6687,7 +6687,7 @@ Clone Activity - Clone Activity + 克隆活动 libs/common/src/lib/routes/routes.ts 129 @@ -6835,7 +6835,7 @@ Oops! Could not delete the asset profile. - Oops! Could not delete the asset profile. + 哎呀!无法删除资产概况。 apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 51 @@ -6939,7 +6939,7 @@ Do you really want to delete these asset profiles? - Do you really want to delete these asset profiles? + 您确定要删除这 个资产概况吗? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 67 @@ -7119,7 +7119,7 @@ Tax Reporting - Tax Reporting + 税务报告 libs/ui/src/lib/i18n.ts 113 @@ -7135,7 +7135,7 @@ Change with currency effect Change - 含货币影响的涨跌 涨跌 + 含货币影响的涨跌 涨跌 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 64 @@ -7151,7 +7151,7 @@ Performance with currency effect Performance - 含货币影响的表现 表现 + 含货币影响的表现 表现 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 84 @@ -7199,7 +7199,7 @@ has been copied to the clipboard - 已复制到剪贴板 + 已复制到剪贴板 apps/client/src/app/components/admin-overview/admin-overview.component.ts 223 @@ -7219,7 +7219,7 @@ Compare Ghostfolio to - - Compare Ghostfolio to - + 对比 Ghostfolio 与 - apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 32 @@ -7267,7 +7267,7 @@ Financial Services - Financial Services + 金融服务 libs/ui/src/lib/i18n.ts 96 @@ -7295,7 +7295,7 @@ Delete - Delete + 删除 apps/client/src/app/components/admin-market-data/admin-market-data.html 270 @@ -7355,7 +7355,7 @@ Dividend Tracking - Dividend Tracking + 股息追踪 libs/ui/src/lib/i18n.ts 106 @@ -7415,7 +7415,7 @@ Investment Research - Investment Research + 投资研究 libs/ui/src/lib/i18n.ts 110 @@ -7697,7 +7697,7 @@ Net Worth Tracking - Net Worth Tracking + 净资产追踪 libs/ui/src/lib/i18n.ts 111 @@ -7769,7 +7769,7 @@ Do you really want to convert the data source to ? - Do you really want to convert the data source to ? + 您确定要把数据源转换为 吗? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 485 @@ -7837,7 +7837,7 @@ Ghostfolio in Numbers: Stars on GitHub - Ghostfolio in Numbers: Stars on GitHub + Ghostfolio 数据:GitHub Stars 数量 apps/client/src/app/pages/landing/landing-page.html 82 @@ -8167,7 +8167,7 @@ ETF Tracking - ETF Tracking + ETF 追踪 libs/ui/src/lib/i18n.ts 107 @@ -8333,7 +8333,7 @@ Post to Ghostfolio on X (formerly Twitter) - Post to Ghostfolio on X (formerly Twitter) + 在 X (前身为 Twitter) 上发布给 Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 85 @@ -8570,7 +8570,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - 如果您遇到错误,想要建议改进或新功能,请加入 Ghostfolio Slack 社区,发布到 @ghostfolio_ + 如果您遇到错误,想要建议改进或新功能,请加入 Ghostfolio Slack 社区,发布到 @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 71 From c3e70091aee0f08389e4ab5a23425839a9a79379 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 23:01:38 +0200 Subject: [PATCH 44/86] Bugfix/validation error caused by empty strings in asset profile details dialog (#7509) * Resolve validation error caused by empty strings * Update changelog --- CHANGELOG.md | 4 ++ .../asset-profile-dialog.component.ts | 16 +++-- .../src/lib/dtos/update-asset-profile.dto.ts | 4 +- libs/common/src/lib/helper.spec.ts | 58 +++++++++++++++++++ libs/common/src/lib/helper.ts | 20 +++++++ 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf5ab1a70..054a24bdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for Chinese (`zh`) +### Fixed + +- Resolved a validation error caused by empty strings in the asset profile details dialog of the admin control panel + ## 3.39.0 - 2026-08-01 ### Changed diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index c5562740f..330688da1 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -11,6 +11,8 @@ import { DATE_FORMAT, getCountryName, getCurrencyFromSymbol, + getStringOrNull, + getStringOrUndefined, isCurrency } from '@ghostfolio/common/helper'; import { @@ -568,9 +570,10 @@ export class GfAssetProfileDialogComponent implements OnInit { this.assetProfileForm.controls.scraperConfiguration.controls.headers .value ?? '{}' ) as Record, - locale: + locale: getStringOrUndefined( this.assetProfileForm.controls.scraperConfiguration.controls.locale - ?.value ?? undefined, + ?.value + ), mode: this.assetProfileForm.controls.scraperConfiguration.controls.mode ?.value ?? undefined, @@ -619,7 +622,7 @@ export class GfAssetProfileDialogComponent implements OnInit { assetClass: this.assetProfileForm.controls.assetClass.value ?? undefined, assetSubClass: this.assetProfileForm.controls.assetSubClass.value ?? undefined, - comment: this.assetProfileForm.controls.comment.value ?? undefined, + comment: getStringOrNull(this.assetProfileForm.controls.comment.value), currency: this.assetProfileForm.controls.currency.value ?? undefined, dataGatheringFrequency: this.assetProfileForm.controls.dataGatheringFrequency.value ?? @@ -628,7 +631,7 @@ export class GfAssetProfileDialogComponent implements OnInit { ? this.assetProfileForm.controls.isActive.value : undefined, name: this.assetProfileForm.controls.name.value ?? undefined, - url: this.assetProfileForm.controls.url.value ?? undefined + url: getStringOrNull(this.assetProfileForm.controls.url.value) }; try { @@ -737,9 +740,10 @@ export class GfAssetProfileDialogComponent implements OnInit { this.assetProfileForm.controls.scraperConfiguration.controls.headers .value ?? '{}' ) as Record, - locale: + locale: getStringOrUndefined( this.assetProfileForm.controls.scraperConfiguration.controls.locale - ?.value ?? undefined, + ?.value + ), mode: this.assetProfileForm.controls.scraperConfiguration.controls .mode?.value, selector: diff --git a/libs/common/src/lib/dtos/update-asset-profile.dto.ts b/libs/common/src/lib/dtos/update-asset-profile.dto.ts index a6e2230e8..a8eaad608 100644 --- a/libs/common/src/lib/dtos/update-asset-profile.dto.ts +++ b/libs/common/src/lib/dtos/update-asset-profile.dto.ts @@ -35,7 +35,7 @@ export class UpdateAssetProfileDto { @IsOptional() @IsString() - comment?: string; + comment?: string | null; @IsArray() @IsOptional() @@ -96,5 +96,5 @@ export class UpdateAssetProfileDto { protocols: ['http', 'https'], require_protocol: true }) - url?: string; + url?: string | null; } diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index d33f10452..758934724 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -1,6 +1,8 @@ import { extractNumberFromString, getNumberFormatGroup, + getStringOrNull, + getStringOrUndefined, isCurrency, isCurrencySymbol } from '@ghostfolio/common/helper'; @@ -139,6 +141,62 @@ describe('Helper', () => { }); }); + describe('Get string or null', () => { + it('String', () => { + expect(getStringOrNull('https://ghostfol.io')).toEqual( + 'https://ghostfol.io' + ); + }); + + it('String (with spaces)', () => { + expect(getStringOrNull(' https://ghostfol.io ')).toEqual( + 'https://ghostfol.io' + ); + }); + + it('Empty string', () => { + expect(getStringOrNull('')).toEqual(null); + }); + + it('Blank string', () => { + expect(getStringOrNull(' ')).toEqual(null); + }); + + it('Null', () => { + expect(getStringOrNull(null)).toEqual(null); + }); + + it('Undefined', () => { + expect(getStringOrNull(undefined)).toEqual(null); + }); + }); + + describe('Get string or undefined', () => { + it('String', () => { + expect(getStringOrUndefined('de-DE')).toEqual('de-DE'); + }); + + it('String (with spaces)', () => { + expect(getStringOrUndefined(' de-DE ')).toEqual('de-DE'); + }); + + it('Empty string', () => { + expect(getStringOrUndefined('')).toEqual(undefined); + }); + + it('Blank string', () => { + expect(getStringOrUndefined(' ')).toEqual(undefined); + }); + + it('Null', () => { + expect(getStringOrUndefined(null)).toEqual(undefined); + }); + + it('Undefined', () => { + expect(getStringOrUndefined(undefined)).toEqual(undefined); + }); + }); + describe('Is currency', () => { it('ISO 4217 currency code', () => { expect(isCurrency('USD')).toEqual(true); diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index db1d3c2a2..7e482838c 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -397,6 +397,26 @@ export function getStartOfUtcDate(aDate: Date) { return date; } +export function getStringOrNull(aString: string | null | undefined) { + const trimmedString = aString?.trim(); + + if (trimmedString) { + return trimmedString; + } + + return null; +} + +export function getStringOrUndefined(aString: string | null | undefined) { + const trimmedString = aString?.trim(); + + if (trimmedString) { + return trimmedString; + } + + return undefined; +} + export function getSum(aArray: Big[]) { if (aArray?.length > 0) { return aArray.reduce((a, b) => a.plus(b), new Big(0)); From fa309b57435df39f0b1ad5a25c2b13c3145e2642 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Aug 2026 23:16:24 +0200 Subject: [PATCH 45/86] Bugfix/handling of Exclude from Analysis tag in activities table (#7511) * Fix handling of Exclude from Analysis tag * Update changelog --- CHANGELOG.md | 1 + libs/common/src/lib/helper.spec.ts | 27 +++++++++++++++++++ libs/common/src/lib/helper.ts | 4 +-- .../activities-table.component.ts | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 054a24bdf..1118f2a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed the handling of the _Exclude from Analysis_ tag in the activities table - Resolved a validation error caused by empty strings in the asset profile details dialog of the admin control panel ## 3.39.0 - 2026-08-01 diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index 758934724..c4947394f 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -1,8 +1,13 @@ +import { + TAG_ID_EMERGENCY_FUND, + TAG_ID_EXCLUDE_FROM_ANALYSIS +} from '@ghostfolio/common/config'; import { extractNumberFromString, getNumberFormatGroup, getStringOrNull, getStringOrUndefined, + isAccountExcluded, isCurrency, isCurrencySymbol } from '@ghostfolio/common/helper'; @@ -197,6 +202,28 @@ describe('Helper', () => { }); }); + describe('Is account excluded', () => { + it('Account with Exclude from Analysis tag', () => { + expect( + isAccountExcluded({ tags: [{ id: TAG_ID_EXCLUDE_FROM_ANALYSIS }] }) + ).toEqual(true); + }); + + it('Account with another tag', () => { + expect( + isAccountExcluded({ tags: [{ id: TAG_ID_EMERGENCY_FUND }] }) + ).toEqual(false); + }); + + it('Account without tags', () => { + expect(isAccountExcluded({ tags: [] })).toEqual(false); + }); + + it('Undefined account', () => { + expect(isAccountExcluded(undefined)).toEqual(false); + }); + }); + describe('Is currency', () => { it('ISO 4217 currency code', () => { expect(isCurrency('USD')).toEqual(true); diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 7e482838c..58927337e 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -476,9 +476,9 @@ export function interpolate(template: string, context: any) { }); } -export function isAccountExcluded(account: { tags?: { id: string }[] }) { +export function isAccountExcluded(account?: { tags?: { id: string }[] }) { return ( - account.tags?.some(({ id }) => { + account?.tags?.some(({ id }) => { return id === TAG_ID_EXCLUDE_FROM_ANALYSIS; }) === true ); diff --git a/libs/ui/src/lib/activities-table/activities-table.component.ts b/libs/ui/src/lib/activities-table/activities-table.component.ts index 6fac6d162..7252b0074 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -298,7 +298,7 @@ export class GfActivitiesTableComponent implements AfterViewInit, OnInit { public isExcludedFromAnalysis(activity: Activity) { return ( - (activity.account && isAccountExcluded(activity.account)) ?? + isAccountExcluded(activity.account) || activity.tags?.some(({ id }) => { return id === TAG_ID_EXCLUDE_FROM_ANALYSIS; }) === true From 6fbf055206aa857f3699b7fd1a86e9899c8d2900 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 09:38:33 +0200 Subject: [PATCH 46/86] Task/upgrade nestjs to version 11.1.28 (#7506) * Update nestjs to version 11.1.28 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 40 ++++++++++++++++++++-------------------- package.json | 8 ++++---- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1118f2a69..5a856ca09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the language localization for Chinese (`zh`) +- Upgraded `nestjs` from version `11.1.27` to `11.1.28` ### Fixed diff --git a/package-lock.json b/package-lock.json index 9009b4f29..51ad39a41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,13 +32,13 @@ "@nest-lab/throttler-storage-redis": "1.2.0", "@nestjs/bull": "11.0.4", "@nestjs/cache-manager": "3.1.3", - "@nestjs/common": "11.1.27", + "@nestjs/common": "11.1.28", "@nestjs/config": "4.0.4", - "@nestjs/core": "11.1.27", + "@nestjs/core": "11.1.28", "@nestjs/event-emitter": "3.1.0", "@nestjs/jwt": "11.0.2", "@nestjs/passport": "11.0.5", - "@nestjs/platform-express": "11.1.27", + "@nestjs/platform-express": "11.1.28", "@nestjs/schedule": "6.1.3", "@nestjs/serve-static": "5.0.5", "@nestjs/throttler": "6.5.0", @@ -116,7 +116,7 @@ "@eslint/eslintrc": "3.3.1", "@eslint/js": "9.35.0", "@nestjs/schematics": "11.1.0", - "@nestjs/testing": "11.1.27", + "@nestjs/testing": "11.1.28", "@nx/angular": "23.0.2", "@nx/eslint-plugin": "23.0.2", "@nx/jest": "23.0.2", @@ -7034,9 +7034,9 @@ } }, "node_modules/@nestjs/common": { - "version": "11.1.27", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.27.tgz", - "integrity": "sha512-kEGSzqM2lWr4whh4Ubflw+oPZSEzxvRMu9WL+LveZploJWTjec5bBlCiRVlVzTPg2kIwBiLwWSvCCW7Wnin1gg==", + "version": "11.1.28", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.28.tgz", + "integrity": "sha512-bRImsxibie+AM7xjdwcrm/gr5YeacI65kSBNzTufa1Ib5iwziaY/lqMtRh9THq6pbV4e1HP9aI2ZxGUumnmaoQ==", "license": "MIT", "dependencies": { "file-type": "21.3.4", @@ -7119,9 +7119,9 @@ } }, "node_modules/@nestjs/core": { - "version": "11.1.27", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.27.tgz", - "integrity": "sha512-K6DX7hcqmZdeXkv7tsPakKBRCgqL19a4mtbX4FluY0hWtFdtPKp6lbe+lb8gWPfvLdbOWr/CPScn7BSjBX+Ecg==", + "version": "11.1.28", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.28.tgz", + "integrity": "sha512-06m63xIRj8+l8uOeh/8LnYupGubkyu4f+bPKIadaSui6vK9KpXgoz7HveT1yOVLcEt0M0oCOEW5EuEXZkEmBBQ==", "license": "MIT", "dependencies": { "fast-safe-stringify": "2.1.1", @@ -7194,14 +7194,14 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "11.1.27", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.27.tgz", - "integrity": "sha512-0ZFhz6H6EdGh4xQVbUNwjoAwBuz73P7FvUAl67h9CTdMqQlJDaQYJApBv8pKfVZ1fGjMCbl0m9DcC6pXaZPWSQ==", + "version": "11.1.28", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.28.tgz", + "integrity": "sha512-hU+9Sz4m+onHrR5AmelI59QKmY/Re546bPnygnpqqeQdHDiJpBgjWbL4t6Jr73CBpS60cpyng7WzjgphNB9iwA==", "license": "MIT", "dependencies": { "cors": "2.8.6", "express": "5.2.1", - "multer": "2.1.1", + "multer": "2.2.0", "path-to-regexp": "8.4.2", "tslib": "2.8.1" }, @@ -7477,9 +7477,9 @@ } }, "node_modules/@nestjs/testing": { - "version": "11.1.27", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.27.tgz", - "integrity": "sha512-I35po13UHZZeGenLWJ3QYwh77RsLau5RcFKWBZ4waVHeARpwjtC7v7n7lGh98swLQdGmZgTnbvKaZ0B5dsUIKA==", + "version": "11.1.28", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.28.tgz", + "integrity": "sha512-B+VgRxeLaH7jkOMgAyUP3N3rpFlisQ7JRxixRbgHvG6a0VgKbbkNSofKExexCgKmQQak80undb3+2kE1lUBmRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -26514,9 +26514,9 @@ } }, "node_modules/multer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", - "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz", + "integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", diff --git a/package.json b/package.json index ded794ce4..7a4d91899 100644 --- a/package.json +++ b/package.json @@ -76,13 +76,13 @@ "@nest-lab/throttler-storage-redis": "1.2.0", "@nestjs/bull": "11.0.4", "@nestjs/cache-manager": "3.1.3", - "@nestjs/common": "11.1.27", + "@nestjs/common": "11.1.28", "@nestjs/config": "4.0.4", - "@nestjs/core": "11.1.27", + "@nestjs/core": "11.1.28", "@nestjs/event-emitter": "3.1.0", "@nestjs/jwt": "11.0.2", "@nestjs/passport": "11.0.5", - "@nestjs/platform-express": "11.1.27", + "@nestjs/platform-express": "11.1.28", "@nestjs/schedule": "6.1.3", "@nestjs/serve-static": "5.0.5", "@nestjs/throttler": "6.5.0", @@ -160,7 +160,7 @@ "@eslint/eslintrc": "3.3.1", "@eslint/js": "9.35.0", "@nestjs/schematics": "11.1.0", - "@nestjs/testing": "11.1.27", + "@nestjs/testing": "11.1.28", "@nx/angular": "23.0.2", "@nx/eslint-plugin": "23.0.2", "@nx/jest": "23.0.2", From b37654c7c6686662d80b517d851401cf2f6c6fa6 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 09:44:05 +0200 Subject: [PATCH 47/86] Bugfix/persistence of empty comment in create or update account dialog (#7512) * Fix persistence of empty comment * Update changelog --- CHANGELOG.md | 1 + .../create-or-update-account-dialog.component.ts | 3 ++- .../create-or-update-activity-dialog.component.ts | 7 +++++-- libs/common/src/lib/dtos/create-account.dto.ts | 2 +- libs/common/src/lib/dtos/create-order.dto.ts | 2 +- libs/common/src/lib/dtos/update-account.dto.ts | 2 +- libs/common/src/lib/dtos/update-order.dto.ts | 2 +- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a856ca09..115d25a92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed the handling of the _Exclude from Analysis_ tag in the activities table +- Fixed the persistence of an empty comment in the create or update account dialog - Resolved a validation error caused by empty strings in the asset profile details dialog of the admin control panel ## 3.39.0 - 2026-08-01 diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts index 8b0536ebf..2157ea5d3 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts @@ -1,6 +1,7 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TAG_ID_EXCLUDE_FROM_ANALYSIS } from '@ghostfolio/common/config'; import { CreateAccountDto, UpdateAccountDto } from '@ghostfolio/common/dtos'; +import { getStringOrNull } from '@ghostfolio/common/helper'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { validateObjectForForm } from '@ghostfolio/common/utils'; import { GfCurrencySelectorComponent } from '@ghostfolio/ui/currency-selector'; @@ -198,7 +199,7 @@ export class GfCreateOrUpdateAccountDialogComponent { protected async onSubmit() { const account: CreateAccountDto | UpdateAccountDto = { balance: this.accountForm.get('balance')?.value, - comment: this.accountForm.get('comment')?.value ?? null, + comment: getStringOrNull(this.accountForm.get('comment')?.value), currency: this.accountForm.get('currency')?.value, id: this.accountForm.get('accountId')?.value, name: this.accountForm.get('name')?.value, diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index 632db1cd4..3b80d2825 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -1,7 +1,10 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { ASSET_CLASS_MAPPING, DEFAULT_LOCALE } from '@ghostfolio/common/config'; import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos'; -import { getDateFormatString } from '@ghostfolio/common/helper'; +import { + getDateFormatString, + getStringOrNull +} from '@ghostfolio/common/helper'; import { AssetClassSelectorOption, LookupItem @@ -471,7 +474,7 @@ export class GfCreateOrUpdateActivityDialogComponent { accountId: this.activityForm.get('accountId')?.value, assetClass: this.activityForm.get('assetClass')?.value, assetSubClass: this.activityForm.get('assetSubClass')?.value, - comment: this.activityForm.get('comment')?.value ?? null, + comment: getStringOrNull(this.activityForm.get('comment')?.value), currency: this.activityForm.get('currency')?.value, customCurrency: this.activityForm.get('currencyOfUnitPrice')?.value, dataSource: ['FEE', 'INTEREST', 'LIABILITY', 'VALUABLE'].includes( diff --git a/libs/common/src/lib/dtos/create-account.dto.ts b/libs/common/src/lib/dtos/create-account.dto.ts index e4a0c64fe..cae8293ee 100644 --- a/libs/common/src/lib/dtos/create-account.dto.ts +++ b/libs/common/src/lib/dtos/create-account.dto.ts @@ -20,7 +20,7 @@ export class CreateAccountDto { @Transform(({ value }: TransformFnParams) => isString(value) ? value.trim() : value ) - comment?: string; + comment?: string | null; @IsCurrencyCode() currency: string; diff --git a/libs/common/src/lib/dtos/create-order.dto.ts b/libs/common/src/lib/dtos/create-order.dto.ts index 36365b7be..c70b66b02 100644 --- a/libs/common/src/lib/dtos/create-order.dto.ts +++ b/libs/common/src/lib/dtos/create-order.dto.ts @@ -35,7 +35,7 @@ export class CreateOrderDto { @Transform(({ value }: TransformFnParams) => isString(value) ? value.trim() : value ) - comment?: string; + comment?: string | null; @IsCurrencyCode() currency: string; diff --git a/libs/common/src/lib/dtos/update-account.dto.ts b/libs/common/src/lib/dtos/update-account.dto.ts index a6a3e6ac6..d8bfc7b8d 100644 --- a/libs/common/src/lib/dtos/update-account.dto.ts +++ b/libs/common/src/lib/dtos/update-account.dto.ts @@ -20,7 +20,7 @@ export class UpdateAccountDto { @Transform(({ value }: TransformFnParams) => isString(value) ? value.trim() : value ) - comment?: string; + comment?: string | null; @IsCurrencyCode() currency: string; diff --git a/libs/common/src/lib/dtos/update-order.dto.ts b/libs/common/src/lib/dtos/update-order.dto.ts index 991479bc8..d8fdbe66b 100644 --- a/libs/common/src/lib/dtos/update-order.dto.ts +++ b/libs/common/src/lib/dtos/update-order.dto.ts @@ -34,7 +34,7 @@ export class UpdateOrderDto { @Transform(({ value }: TransformFnParams) => isString(value) ? value.trim() : value ) - comment?: string; + comment?: string | null; @IsCurrencyCode() currency: string; From cb775af7f1631ac95436db65f8730baceb296e48 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 09:51:39 +0200 Subject: [PATCH 48/86] Task/improve style of read-only tags in tags selector component (#7504) * Improve style of read-only tags * Add Storybook story * Update changelog --- CHANGELOG.md | 1 + .../src/lib/tags-selector/tags-selector.component.html | 10 +++++----- .../tags-selector/tags-selector.component.stories.ts | 8 ++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 115d25a92..9fe7f1a8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the style of the read-only tags in the tags selector component - Improved the language localization for Chinese (`zh`) - Upgraded `nestjs` from version `11.1.27` to `11.1.28` diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.html b/libs/ui/src/lib/tags-selector/tags-selector.component.html index bd56e9318..9bede09a7 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.html +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1,20 +1,20 @@
@if (readonly) { -
Tags
+
Tags
@if ( tagsSelected().length > 0 || (tagsReadOnly && tagsReadOnly.length > 0) ) { - + @if (tagsReadOnly) { @for (tag of tagsReadOnly; track tag.id) { - {{ tag.name }} + {{ tag.name }} } } @for (tag of tagsSelected(); track tag.id) { - {{ tag.name }} + {{ tag.name }} } - + } @else {
} diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts index 48aeaffe3..e8bdd1873 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts @@ -87,6 +87,14 @@ export const Readonly: Story = { } }; +export const ReadonlyWithoutValue: Story = { + args: { + readonly: true, + tags: [], + tagsAvailable: OPTIONS + } +}; + export const WithoutValue: Story = { args: { tags: [], From bd8ef423fae22709c70c901bab2c4ca42ba74f7b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 09:57:21 +0200 Subject: [PATCH 49/86] Release 3.40.0 (#7514) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fe7f1a8b..c32132bc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 3.40.0 - 2026-08-02 ### Changed diff --git a/package-lock.json b/package-lock.json index 51ad39a41..b39eac00d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.39.0", + "version": "3.40.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.39.0", + "version": "3.40.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 7a4d91899..dc1e12020 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.39.0", + "version": "3.40.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From ddf446f9156243a140b3bed6ab8a70215c81193e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 17:00:13 +0200 Subject: [PATCH 50/86] Feature/stock splits setup (#7251) * Stock splits setup * Update changelog --- CHANGELOG.md | 4 + apps/api/src/app/asset/asset.controller.ts | 3 +- .../asset-profiles.controller.ts | 96 ++++++++++++- .../asset-profiles/asset-profiles.module.ts | 2 + .../asset-profiles/asset-profiles.service.ts | 45 ++++++- apps/api/src/app/user/user.service.ts | 2 + .../asset-profile-split.module.ts | 12 ++ .../asset-profile-split.service.ts | 87 ++++++++++++ .../asset-profile-dialog.component.ts | 85 +++++++++++- .../asset-profile-dialog.html | 127 ++++++++++++++++++ .../dtos/create-asset-profile-split.dto.ts | 39 ++++++ libs/common/src/lib/dtos/index.ts | 2 + libs/common/src/lib/helper.spec.ts | 48 ++++++- libs/common/src/lib/helper.ts | 22 +++ .../admin-market-data-details.interface.ts | 3 +- .../asset-profile-response.interface.ts | 3 +- libs/common/src/lib/permissions.ts | 12 ++ .../validator-constraints/is-split-ratio.ts | 18 +++ libs/ui/src/lib/services/admin.service.ts | 24 +++- libs/ui/src/lib/services/data.service.ts | 4 + .../migration.sql | 21 +++ prisma/schema.prisma | 28 ++++ 22 files changed, 674 insertions(+), 13 deletions(-) create mode 100644 apps/api/src/services/asset-profile-split/asset-profile-split.module.ts create mode 100644 apps/api/src/services/asset-profile-split/asset-profile-split.service.ts create mode 100644 libs/common/src/lib/dtos/create-asset-profile-split.dto.ts create mode 100644 libs/common/src/lib/validator-constraints/is-split-ratio.ts create mode 100644 prisma/migrations/20260802000000_added_asset_profile_split/migration.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index c32132bc9..53c443900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 3.40.0 - 2026-08-02 +### Added + +- Added the database model and endpoints to manage the stock splits of an asset profile (experimental) + ### Changed - Improved the style of the read-only tags in the tags selector component diff --git a/apps/api/src/app/asset/asset.controller.ts b/apps/api/src/app/asset/asset.controller.ts index de04b5c81..49afb43d7 100644 --- a/apps/api/src/app/asset/asset.controller.ts +++ b/apps/api/src/app/asset/asset.controller.ts @@ -20,7 +20,7 @@ export class AssetController { @Param('dataSource') dataSource: DataSource, @Param('symbol') symbol: string ): Promise { - const { assetProfile, marketData } = + const { assetProfile, marketData, splits } = await this.assetProfilesService.getAssetProfile({ dataSource, symbol @@ -28,6 +28,7 @@ export class AssetController { return { marketData, + splits, assetProfile: pick(assetProfile, ['dataSource', 'name', 'symbol']) }; } diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts index 6be23c269..6521665e1 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts @@ -4,7 +4,10 @@ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interce import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; -import { UpdateAssetProfileDataDto } from '@ghostfolio/common/dtos'; +import { + CreateAssetProfileSplitDto, + UpdateAssetProfileDataDto +} from '@ghostfolio/common/dtos'; import { getCurrencyFromSymbol, isCurrency } from '@ghostfolio/common/helper'; import { AssetProfileResponse } from '@ghostfolio/common/interfaces'; import { @@ -18,19 +21,22 @@ import { MarketDataPreset, RequestWithUser } from '@ghostfolio/common/types'; import { Body, Controller, + Delete, Get, HttpException, Inject, Param, ParseIntPipe, Patch, + Post, Query, UseGuards, UseInterceptors } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { DataSource, Prisma } from '@prisma/client'; +import { AssetProfileSplit, DataSource, Prisma } from '@prisma/client'; +import { parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { AssetProfilesService } from './asset-profiles.service'; @@ -119,6 +125,49 @@ export class AssetProfilesController { }); } + @Post(':dataSource/:symbol/splits') + @UseGuards(AuthGuard('jwt')) + @UseInterceptors(TransformDataSourceInRequestInterceptor) + public async createSplit( + @Body() data: CreateAssetProfileSplitDto, + @Param('dataSource') dataSource: DataSource, + @Param('symbol') symbol: string + ): Promise { + const { id: symbolProfileId } = await this.validateAccessToSplits({ + dataSource, + symbol, + permission: permissions.createAssetProfileSplit, + permissionOfOwnAssetProfile: + permissions.createAssetProfileSplitOfOwnAssetProfile + }); + + return this.assetProfilesService.createSplit({ + symbolProfileId, + date: parseISO(data.date), + denominator: data.denominator, + numerator: data.numerator + }); + } + + @Delete(':dataSource/:symbol/splits/:id') + @UseGuards(AuthGuard('jwt')) + @UseInterceptors(TransformDataSourceInRequestInterceptor) + public async deleteSplit( + @Param('dataSource') dataSource: DataSource, + @Param('id') id: string, + @Param('symbol') symbol: string + ): Promise { + const { id: symbolProfileId } = await this.validateAccessToSplits({ + dataSource, + symbol, + permission: permissions.deleteAssetProfileSplit, + permissionOfOwnAssetProfile: + permissions.deleteAssetProfileSplitOfOwnAssetProfile + }); + + return this.assetProfilesService.deleteSplit({ id, symbolProfileId }); + } + @HasPermission(permissions.accessAdminControl) @Patch(':dataSource/:symbol') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @@ -139,4 +188,47 @@ export class AssetProfilesController { assetProfileData ); } + + private async validateAccessToSplits({ + dataSource, + permission, + permissionOfOwnAssetProfile, + symbol + }: { + dataSource: DataSource; + permission: string; + permissionOfOwnAssetProfile: string; + symbol: string; + }) { + const [assetProfile] = await this.symbolProfileService.getSymbolProfiles([ + { dataSource, symbol } + ]); + + if (!assetProfile) { + throw new HttpException( + getReasonPhrase(StatusCodes.NOT_FOUND), + StatusCodes.NOT_FOUND + ); + } + + const canAccessAllAssetProfiles = hasPermission( + this.request.user.permissions, + permission + ); + + const canAccessOwnAssetProfile = + assetProfile.userId === this.request.user.id && + hasPermission(this.request.user.permissions, permissionOfOwnAssetProfile); + + if (!canAccessAllAssetProfiles && !canAccessOwnAssetProfile) { + throw new HttpException( + assetProfile.userId + ? getReasonPhrase(StatusCodes.NOT_FOUND) + : getReasonPhrase(StatusCodes.FORBIDDEN), + assetProfile.userId ? StatusCodes.NOT_FOUND : StatusCodes.FORBIDDEN + ); + } + + return assetProfile; + } } diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts index f96d92eb3..e3906be9f 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts @@ -2,6 +2,7 @@ import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.modu import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; +import { AssetProfileSplitModule } from '@ghostfolio/api/services/asset-profile-split/asset-profile-split.module'; import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; @@ -20,6 +21,7 @@ import { AssetProfilesService } from './asset-profiles.service'; imports: [ ActivitiesModule, ApiModule, + AssetProfileSplitModule, BenchmarkModule, DataProviderModule, ExchangeRateDataModule, diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts index bc6aeff1e..7d75fc40b 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts @@ -1,4 +1,5 @@ import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; +import { AssetProfileSplitService } from '@ghostfolio/api/services/asset-profile-split/asset-profile-split.service'; import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; @@ -30,6 +31,7 @@ import { groupBy } from 'lodash'; export class AssetProfilesService { public constructor( private readonly activitiesService: ActivitiesService, + private readonly assetProfileSplitService: AssetProfileSplitService, private readonly benchmarkService: BenchmarkService, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, @@ -38,6 +40,42 @@ export class AssetProfilesService { private readonly symbolProfileService: SymbolProfileService ) {} + public async createSplit({ + date, + denominator, + numerator, + symbolProfileId + }: { + date: Date; + denominator: number; + numerator: number; + symbolProfileId: string; + }) { + return this.assetProfileSplitService.upsert({ + date, + denominator, + numerator, + symbolProfileId + }); + } + + public async deleteSplit({ + id, + symbolProfileId + }: { + id: string; + symbolProfileId: string; + }) { + const isDeleted = await this.assetProfileSplitService.deleteById({ + id, + symbolProfileId + }); + + if (!isDeleted) { + throw new NotFoundException(); + } + } + public async getAssetProfile({ dataSource, symbol @@ -54,7 +92,7 @@ export class AssetProfilesService { await this.activitiesService.getStatisticsByCurrency(currency)); } - const [[assetProfile], marketData] = await Promise.all([ + const [[assetProfile], marketData, splits] = await Promise.all([ this.symbolProfileService.getSymbolProfiles([ { dataSource, @@ -69,7 +107,8 @@ export class AssetProfilesService { dataSource, symbol } - }) + }), + this.assetProfileSplitService.getSplits({ dataSource, symbol }) ]); if (assetProfile) { @@ -80,6 +119,7 @@ export class AssetProfilesService { return { marketData, + splits, assetProfile: assetProfile ?? { activitiesCount, currency, @@ -92,6 +132,7 @@ export class AssetProfilesService { } }; } + public async getAssetProfiles({ filters = [], presetId, diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index b706e4702..5d60c571d 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -549,9 +549,11 @@ export class UserService { currentPermissions, permissions.accessHoldingsChart, permissions.createAccess, + permissions.createAssetProfileSplitOfOwnAssetProfile, permissions.createMarketDataOfOwnAssetProfile, permissions.createOwnTag, permissions.createWatchlistItem, + permissions.deleteAssetProfileSplitOfOwnAssetProfile, permissions.readAiPrompt, permissions.readMarketDataOfOwnAssetProfile, permissions.updateMarketDataOfOwnAssetProfile diff --git a/apps/api/src/services/asset-profile-split/asset-profile-split.module.ts b/apps/api/src/services/asset-profile-split/asset-profile-split.module.ts new file mode 100644 index 000000000..1219a2f98 --- /dev/null +++ b/apps/api/src/services/asset-profile-split/asset-profile-split.module.ts @@ -0,0 +1,12 @@ +import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; + +import { Module } from '@nestjs/common'; + +import { AssetProfileSplitService } from './asset-profile-split.service'; + +@Module({ + exports: [AssetProfileSplitService], + imports: [PrismaModule], + providers: [AssetProfileSplitService] +}) +export class AssetProfileSplitModule {} diff --git a/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts b/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts new file mode 100644 index 000000000..ec842caaf --- /dev/null +++ b/apps/api/src/services/asset-profile-split/asset-profile-split.service.ts @@ -0,0 +1,87 @@ +import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { resetHours } from '@ghostfolio/common/helper'; +import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; + +import { Injectable } from '@nestjs/common'; +import { AssetProfileSplit } from '@prisma/client'; + +@Injectable() +export class AssetProfileSplitService { + public constructor(private readonly prismaService: PrismaService) {} + + /** + * Deletes the split with the given id of an asset profile and returns + * whether it existed + */ + public async deleteById({ + id, + symbolProfileId + }: { + id: string; + symbolProfileId: string; + }) { + const { count } = await this.prismaService.assetProfileSplit.deleteMany({ + where: { + id, + symbolProfileId + } + }); + + return count > 0; + } + + /** + * Returns the splits of the given asset profile in ascending order by date + */ + public async getSplits({ + dataSource, + symbol + }: AssetProfileIdentifier): Promise { + return this.prismaService.assetProfileSplit.findMany({ + orderBy: [ + { + date: 'asc' + } + ], + where: { + symbolProfile: { + dataSource, + symbol + } + } + }); + } + + public async upsert({ + date, + denominator, + numerator, + symbolProfileId + }: { + date: Date; + denominator: number; + numerator: number; + symbolProfileId: string; + }): Promise { + const dateOfSplit = resetHours(date); + + return this.prismaService.assetProfileSplit.upsert({ + create: { + denominator, + numerator, + symbolProfileId, + date: dateOfSplit + }, + update: { + denominator, + numerator + }, + where: { + symbolProfileId_date: { + symbolProfileId, + date: dateOfSplit + } + } + }); + } +} diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index 330688da1..f0e8eaf17 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -11,9 +11,11 @@ import { DATE_FORMAT, getCountryName, getCurrencyFromSymbol, + getDateFormatString, getStringOrNull, getStringOrUndefined, - isCurrency + isCurrency, + isSplitRatio } from '@ghostfolio/common/helper'; import { AdminMarketDataDetails, @@ -37,6 +39,7 @@ import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplet import { GfValueComponent } from '@ghostfolio/ui/value'; import { TextFieldModule } from '@angular/cdk/text-field'; +import { CommonModule } from '@angular/common'; import { HttpErrorResponse } from '@angular/common/http'; import { ChangeDetectionStrategy, @@ -63,6 +66,7 @@ import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MAT_DIALOG_DATA, MatDialogModule, @@ -76,6 +80,7 @@ import { MatTabsModule } from '@angular/material/tabs'; import { IonIcon } from '@ionic/angular/standalone'; import { AssetClass, + AssetProfileSplit, AssetSubClass, DataGatheringFrequency, DataSource, @@ -88,11 +93,14 @@ import { format } from 'date-fns'; import { StatusCodes } from 'http-status-codes'; import { addIcons } from 'ionicons'; import { + calendarClearOutline, codeSlashOutline, createOutline, ellipsisVertical, + gitCompareOutline, readerOutline, - serverOutline + serverOutline, + trashOutline } from 'ionicons/icons'; import { isBoolean } from 'lodash'; import ms from 'ms'; @@ -105,6 +113,7 @@ import { AssetProfileDialogParams } from './interfaces/interfaces'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'd-flex flex-column h-100' }, imports: [ + CommonModule, FormsModule, GfCurrencySelectorComponent, GfEntityLogoComponent, @@ -116,6 +125,7 @@ import { AssetProfileDialogParams } from './interfaces/interfaces'; IonIcon, MatButtonModule, MatCheckboxModule, + MatDatepickerModule, MatDialogModule, MatInputModule, MatMenuModule, @@ -196,6 +206,26 @@ export class GfAssetProfileDialogComponent implements OnInit { } ); + protected readonly assetProfileSplitForm = this.formBuilder.group( + { + date: new FormControl(null, Validators.required), + denominator: new FormControl(null, Validators.required), + numerator: new FormControl(null, Validators.required) + }, + { + validators: (control: AbstractControl): ValidationErrors | null => { + const { denominator, numerator } = control.value as { + denominator: number; + numerator: number; + }; + + return isSplitRatio({ denominator, numerator }) + ? null + : { invalidSplitRatio: true }; + } + } + ); + protected readonly canDeleteAssetProfile = canDeleteAssetProfile; protected canEditAssetProfile = true; @@ -247,6 +277,7 @@ export class GfAssetProfileDialogComponent implements OnInit { value: 'max' } ]; + protected defaultDateFormat: string; protected readonly getCountryName = getCountryName; protected historicalDataItems: LineChartItem[]; protected isBenchmark = false; @@ -270,6 +301,8 @@ export class GfAssetProfileDialogComponent implements OnInit { [name: string]: { name: string; value: number }; }; + protected splits: AssetProfileSplit[] = []; + protected readonly translate = translate; protected user: User; @@ -293,11 +326,14 @@ export class GfAssetProfileDialogComponent implements OnInit { private userService: UserService ) { addIcons({ + calendarClearOutline, codeSlashOutline, createOutline, ellipsisVertical, + gitCompareOutline, readerOutline, - serverOutline + serverOutline, + trashOutline }); } @@ -310,6 +346,7 @@ export class GfAssetProfileDialogComponent implements OnInit { this.benchmarks = benchmarks; this.currencies = currencies; + this.defaultDateFormat = getDateFormatString(this.data.locale); this.initialize(); } @@ -364,8 +401,9 @@ export class GfAssetProfileDialogComponent implements OnInit { symbol: this.data.symbol }) .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(({ assetProfile, marketData }) => { + .subscribe(({ assetProfile, marketData, splits }) => { this.assetProfile = assetProfile; + this.splits = splits ?? []; this.assetClassLabel = translate(this.assetProfile?.assetClass ?? ''); this.assetSubClassLabel = translate( @@ -521,6 +559,45 @@ export class GfAssetProfileDialogComponent implements OnInit { .subscribe(); } + protected onAddSplit() { + const { date, denominator, numerator } = + this.assetProfileSplitForm.getRawValue(); + + if (!date || !denominator || !numerator) { + return; + } + + this.adminService + .postAssetProfileSplit({ + dataSource: this.data.dataSource, + split: { + denominator, + numerator, + date: format(date, DATE_FORMAT) + }, + symbol: this.data.symbol + }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.assetProfileSplitForm.reset(); + + this.initialize(); + }); + } + + protected onDeleteSplit(aId: string) { + this.adminService + .deleteAssetProfileSplit({ + dataSource: this.data.dataSource, + id: aId, + symbol: this.data.symbol + }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.initialize(); + }); + } + protected onMarketDataChanged(withRefresh: boolean = false) { if (withRefresh) { this.initialize(); diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index f0b914b1c..f5df34ab4 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -503,6 +503,133 @@
+ + @if (false && user?.settings?.isExperimentalFeatures) { + + + +
Splits
+
+
+
+
+

+ Splits are stored for this asset profile, but are not applied + to the portfolio calculation yet. +

+ @if (splits.length > 0) { + + + + + + + + + + @for (split of splits; track split.id) { + + + + + + } + +
Date + Split Ratio +
+ {{ split.date | date: defaultDateFormat }} + + {{ split.numerator }}:{{ split.denominator }} + + +
+ } +
+ + Date + + + + + + + + Shares After + + Numerator, + e.g. 4 for a 4:1 split or 1 for a 1:10 reverse + split + + + Shares Before + + Denominator, + e.g. 1 for a 4:1 split or 10 for a 1:10 reverse + split + +
+ +
+
+
+
+
+
+ } @if (assetProfile?.dataSource === 'MANUAL') { diff --git a/libs/common/src/lib/dtos/create-asset-profile-split.dto.ts b/libs/common/src/lib/dtos/create-asset-profile-split.dto.ts new file mode 100644 index 000000000..a68f00883 --- /dev/null +++ b/libs/common/src/lib/dtos/create-asset-profile-split.dto.ts @@ -0,0 +1,39 @@ +import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970'; +import { IsSplitRatioConstraint } from '@ghostfolio/common/validator-constraints/is-split-ratio'; + +import { IsInt, IsISO8601, Validate } from 'class-validator'; + +export class CreateAssetProfileSplitDto { + /** + * The date the split becomes effective. Activities before this date are + * adjusted by the ratio. + */ + @IsISO8601() + @Validate(IsAfter1970Constraint) + date: string; + + /** + * The number of shares held before the split, for example 1 for a 4:1 split + * or 10 for a 1:10 reverse split. + */ + @IsInt() + denominator: number; + + /** + * The number of shares held after the split, for example 4 for a 4:1 split + * or 1 for a 1:10 reverse split. + * + * The resulting split factor is numerator / denominator. Both parts are kept + * so that the ratio stays exact, for example 1/3 for a 1:3 reverse split. + * + * Activities are adjusted by this ratio: the quantity is multiplied by it and + * the unit price divided by it, so that the total value of an activity stays + * the same. + * + * Market data is already split-adjusted by the data providers and must not be + * adjusted again. + */ + @IsInt() + @Validate(IsSplitRatioConstraint) + numerator: number; +} diff --git a/libs/common/src/lib/dtos/index.ts b/libs/common/src/lib/dtos/index.ts index 785115356..7cf385cd7 100644 --- a/libs/common/src/lib/dtos/index.ts +++ b/libs/common/src/lib/dtos/index.ts @@ -4,6 +4,7 @@ import { CreateAccessDto } from './create-access.dto'; import { CreateAccountBalanceDto } from './create-account-balance.dto'; import { CreateAccountWithBalancesDto } from './create-account-with-balances.dto'; import { CreateAccountDto } from './create-account.dto'; +import { CreateAssetProfileSplitDto } from './create-asset-profile-split.dto'; import { CreateAssetProfileWithMarketDataDto } from './create-asset-profile-with-market-data.dto'; import { CreateAssetProfileDto } from './create-asset-profile.dto'; import { CreateOrderDto } from './create-order.dto'; @@ -36,6 +37,7 @@ export { CreateAccountDto, CreateAccountWithBalancesDto, CreateAssetProfileDto, + CreateAssetProfileSplitDto, CreateAssetProfileWithMarketDataDto, CreateOrderDto, CreatePlatformDto, diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index c4947394f..42441a619 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -9,7 +9,8 @@ import { getStringOrUndefined, isAccountExcluded, isCurrency, - isCurrencySymbol + isCurrencySymbol, + isSplitRatio } from '@ghostfolio/common/helper'; describe('Helper', () => { @@ -280,4 +281,49 @@ describe('Helper', () => { expect(isCurrencySymbol('')).toEqual(false); }); }); + + describe('Is split ratio', () => { + it('Forward split', () => { + expect(isSplitRatio({ denominator: 1, numerator: 2 })).toEqual(true); + expect(isSplitRatio({ denominator: 1, numerator: 4 })).toEqual(true); + expect(isSplitRatio({ denominator: 2, numerator: 3 })).toEqual(true); + }); + + it('Reverse split', () => { + expect(isSplitRatio({ denominator: 10, numerator: 1 })).toEqual(true); + expect(isSplitRatio({ denominator: 3, numerator: 1 })).toEqual(true); + }); + + it('Ratio without effect', () => { + expect(isSplitRatio({ denominator: 1, numerator: 1 })).toEqual(false); + expect(isSplitRatio({ denominator: 3, numerator: 3 })).toEqual(false); + }); + + it('Zero or negative ratio', () => { + expect(isSplitRatio({ denominator: 1, numerator: 0 })).toEqual(false); + expect(isSplitRatio({ denominator: 0, numerator: 1 })).toEqual(false); + expect(isSplitRatio({ denominator: 1, numerator: -2 })).toEqual(false); + expect(isSplitRatio({ denominator: -2, numerator: 1 })).toEqual(false); + }); + + it('Non-integer ratio', () => { + expect(isSplitRatio({ denominator: 1, numerator: 1.5 })).toEqual(false); + expect(isSplitRatio({ denominator: 2.5, numerator: 1 })).toEqual(false); + expect(isSplitRatio({ denominator: 1, numerator: Number.NaN })).toEqual( + false + ); + expect( + isSplitRatio({ denominator: 1, numerator: Number.POSITIVE_INFINITY }) + ).toEqual(false); + }); + + it('Missing ratio', () => { + expect( + isSplitRatio({ denominator: undefined, numerator: undefined }) + ).toEqual(false); + expect(isSplitRatio({ denominator: null, numerator: null })).toEqual( + false + ); + }); + }); }); diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 58927337e..22f969d02 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -526,6 +526,28 @@ export function isRootCurrency(aCurrency: string) { }); } +/** + * Validates the ratio of a stock split, expressed as the number of shares held + * after the split (numerator) per number of shares held before (denominator), + * for example 4 and 1 for a 4:1 split or 1 and 10 for a 1:10 reverse split. An + * equal numerator and denominator would be a no-op. + */ +export function isSplitRatio({ + denominator, + numerator +}: { + denominator: number; + numerator: number; +}) { + return ( + Number.isSafeInteger(numerator) && + Number.isSafeInteger(denominator) && + numerator > 0 && + denominator > 0 && + numerator !== denominator + ); +} + export function isValidSearchQuery(aQuery: string) { return aQuery?.trim().length >= SEARCH_QUERY_MINIMUM_LENGTH; } diff --git a/libs/common/src/lib/interfaces/admin-market-data-details.interface.ts b/libs/common/src/lib/interfaces/admin-market-data-details.interface.ts index dc44d0382..8cfe70f9c 100644 --- a/libs/common/src/lib/interfaces/admin-market-data-details.interface.ts +++ b/libs/common/src/lib/interfaces/admin-market-data-details.interface.ts @@ -1,8 +1,9 @@ -import { MarketData } from '@prisma/client'; +import { AssetProfileSplit, MarketData } from '@prisma/client'; import { EnhancedAssetProfile } from './enhanced-asset-profile.interface'; export interface AdminMarketDataDetails { assetProfile: Partial; marketData: MarketData[]; + splits: AssetProfileSplit[]; } diff --git a/libs/common/src/lib/interfaces/responses/asset-profile-response.interface.ts b/libs/common/src/lib/interfaces/responses/asset-profile-response.interface.ts index d76188c73..26082c2c4 100644 --- a/libs/common/src/lib/interfaces/responses/asset-profile-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/asset-profile-response.interface.ts @@ -1,8 +1,9 @@ -import { MarketData } from '@prisma/client'; +import { AssetProfileSplit, MarketData } from '@prisma/client'; import { EnhancedAssetProfile } from '../enhanced-asset-profile.interface'; export interface AssetProfileResponse { assetProfile: Partial; marketData: MarketData[]; + splits: AssetProfileSplit[]; } diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index 428de1788..811ded68c 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -12,6 +12,9 @@ export const permissions = { createAccountBalance: 'createAccountBalance', createActivity: 'createActivity', createApiKey: 'createApiKey', + createAssetProfileSplit: 'createAssetProfileSplit', + createAssetProfileSplitOfOwnAssetProfile: + 'createAssetProfileSplitOfOwnAssetProfile', createMarketData: 'createMarketData', createMarketDataOfOwnAssetProfile: 'createMarketDataOfOwnAssetProfile', createOwnTag: 'createOwnTag', @@ -23,6 +26,9 @@ export const permissions = { deleteAccount: 'deleteAccount', deleteAccountBalance: 'deleteAccountBalance', deleteActivity: 'deleteActivity', + deleteAssetProfileSplit: 'deleteAssetProfileSplit', + deleteAssetProfileSplitOfOwnAssetProfile: + 'deleteAssetProfileSplitOfOwnAssetProfile', deleteAuthDevice: 'deleteAuthDevice', deleteOwnUser: 'deleteOwnUser', deletePlatform: 'deletePlatform', @@ -80,6 +86,8 @@ export function getPermissions(aRole: Role): string[] { permissions.createWatchlistItem, permissions.deleteAccountBalance, permissions.deleteWatchlistItem, + permissions.createAssetProfileSplit, + permissions.createAssetProfileSplitOfOwnAssetProfile, permissions.createMarketData, permissions.createMarketDataOfOwnAssetProfile, permissions.createOwnTag, @@ -88,6 +96,8 @@ export function getPermissions(aRole: Role): string[] { permissions.deleteAccess, permissions.deleteAccount, permissions.deleteActivity, + permissions.deleteAssetProfileSplit, + permissions.deleteAssetProfileSplitOfOwnAssetProfile, permissions.deleteAuthDevice, permissions.deletePlatform, permissions.deleteTag, @@ -128,6 +138,7 @@ export function getPermissions(aRole: Role): string[] { permissions.createAccount, permissions.createAccountBalance, permissions.createActivity, + permissions.createAssetProfileSplitOfOwnAssetProfile, permissions.createMarketDataOfOwnAssetProfile, permissions.createOwnTag, permissions.createWatchlistItem, @@ -135,6 +146,7 @@ export function getPermissions(aRole: Role): string[] { permissions.deleteAccount, permissions.deleteAccountBalance, permissions.deleteActivity, + permissions.deleteAssetProfileSplitOfOwnAssetProfile, permissions.deleteAuthDevice, permissions.deleteWatchlistItem, permissions.readAiPrompt, diff --git a/libs/common/src/lib/validator-constraints/is-split-ratio.ts b/libs/common/src/lib/validator-constraints/is-split-ratio.ts new file mode 100644 index 000000000..d3cd454e8 --- /dev/null +++ b/libs/common/src/lib/validator-constraints/is-split-ratio.ts @@ -0,0 +1,18 @@ +import { isSplitRatio } from '@ghostfolio/common/helper'; + +import { + ValidationArguments, + ValidatorConstraint, + ValidatorConstraintInterface +} from 'class-validator'; + +@ValidatorConstraint({ name: 'isSplitRatio' }) +export class IsSplitRatioConstraint implements ValidatorConstraintInterface { + public defaultMessage() { + return 'numerator and denominator must be different positive integers'; + } + + public validate(_: unknown, { object }: ValidationArguments) { + return isSplitRatio(object as { denominator: number; numerator: number }); + } +} diff --git a/libs/ui/src/lib/services/admin.service.ts b/libs/ui/src/lib/services/admin.service.ts index 6a06ef76b..8510f1729 100644 --- a/libs/ui/src/lib/services/admin.service.ts +++ b/libs/ui/src/lib/services/admin.service.ts @@ -4,6 +4,7 @@ import { HEADER_KEY_TOKEN } from '@ghostfolio/common/config'; import { + CreateAssetProfileSplitDto, CreatePlatformDto, UpdateAssetProfileDto, UpdatePlatformDto @@ -23,7 +24,7 @@ import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable, inject } from '@angular/core'; -import { MarketData, Platform } from '@prisma/client'; +import { AssetProfileSplit, MarketData, Platform } from '@prisma/client'; import { JobStatus } from 'bull'; import { isNumber } from 'lodash'; @@ -61,6 +62,16 @@ export class AdminService { return this.http.delete(`/api/v1/platform/${aId}`); } + public deleteAssetProfileSplit({ + dataSource, + id, + symbol + }: AssetProfileIdentifier & { id: string }) { + return this.http.delete( + `/api/v1/asset-profiles/${dataSource}/${encodeURIComponent(symbol)}/splits/${id}` + ); + } + public deleteProfileData({ dataSource, symbol }: AssetProfileIdentifier) { return this.http.delete( `/api/v1/admin/profile-data/${dataSource}/${encodeURIComponent(symbol)}` @@ -217,6 +228,17 @@ export class AdminService { ); } + public postAssetProfileSplit({ + dataSource, + split, + symbol + }: AssetProfileIdentifier & { split: CreateAssetProfileSplitDto }) { + return this.http.post( + `/api/v1/asset-profiles/${dataSource}/${encodeURIComponent(symbol)}/splits`, + split + ); + } + public postPlatform(aPlatform: CreatePlatformDto) { return this.http.post(`/api/v1/platform`, aPlatform); } diff --git a/libs/ui/src/lib/services/data.service.ts b/libs/ui/src/lib/services/data.service.ts index bc1512550..7ccd9d1d9 100644 --- a/libs/ui/src/lib/services/data.service.ts +++ b/libs/ui/src/lib/services/data.service.ts @@ -589,6 +589,10 @@ export class DataService { item.date = parseISO(item.date); } + for (const item of data.splits ?? []) { + item.date = parseISO(item.date); + } + return data; }) ); diff --git a/prisma/migrations/20260802000000_added_asset_profile_split/migration.sql b/prisma/migrations/20260802000000_added_asset_profile_split/migration.sql new file mode 100644 index 000000000..9003916b4 --- /dev/null +++ b/prisma/migrations/20260802000000_added_asset_profile_split/migration.sql @@ -0,0 +1,21 @@ +-- CreateTable +CREATE TABLE "AssetProfileSplit" ( + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "date" TIMESTAMP(3) NOT NULL, + "denominator" INTEGER NOT NULL, + "id" TEXT NOT NULL, + "numerator" INTEGER NOT NULL, + "symbolProfileId" TEXT NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AssetProfileSplit_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "AssetProfileSplit_date_idx" ON "AssetProfileSplit"("date"); + +-- CreateIndex +CREATE UNIQUE INDEX "AssetProfileSplit_symbolProfileId_date_key" ON "AssetProfileSplit"("symbolProfileId", "date"); + +-- AddForeignKey +ALTER TABLE "AssetProfileSplit" ADD CONSTRAINT "AssetProfileSplit_symbolProfileId_fkey" FOREIGN KEY ("symbolProfileId") REFERENCES "SymbolProfile"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index faf7a9259..77faccd49 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -116,6 +116,33 @@ model AssetProfileResolution { @@unique([dataSourceOrigin, symbolOrigin]) } +/// A stock split of an asset profile. The numerator is the number of shares +/// held after the split, the denominator the number of shares held before, for +/// example 4 and 1 for a 4:1 split or 1 and 10 for a 1:10 reverse split. +/// +/// The ratio is stored as two integers instead of the resulting factor, so that +/// it stays exact, for example 1/3 for a 1:3 reverse split. +/// +/// Activities before the date are adjusted by the ratio: the quantity is +/// multiplied by it and the unit price divided by it, so that the total value +/// of an activity stays the same. +/// +/// Market data is already split-adjusted by the data providers and must not be +/// adjusted again. +model AssetProfileSplit { + createdAt DateTime @default(now()) + date DateTime + denominator Int + id String @id @default(uuid()) + numerator Int + symbolProfile SymbolProfile @relation(fields: [symbolProfileId], onDelete: Cascade, references: [id]) + symbolProfileId String + updatedAt DateTime @updatedAt + + @@unique([symbolProfileId, date]) + @@index([date]) +} + model AuthDevice { createdAt DateTime @default(now()) credentialId Bytes @@ -200,6 +227,7 @@ model SymbolProfile { activities Order[] assetClass AssetClass? assetProfileOverrides AssetProfileOverrides? + assetProfileSplits AssetProfileSplit[] assetSubClass AssetSubClass? comment String? countries Json? From 70eaf0999a5829e7595e712e38ddde19c31c247b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 17:17:01 +0200 Subject: [PATCH 51/86] Bugfix/changelog entry of stock splits (#7516) Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c443900..38e3855f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 3.40.0 - 2026-08-02 +## Unreleased ### Added - Added the database model and endpoints to manage the stock splits of an asset profile (experimental) +## 3.40.0 - 2026-08-02 + ### Changed - Improved the style of the read-only tags in the tags selector component From d08239f31f8795b2424ce6299bf9451c6225b66b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:00:52 +0200 Subject: [PATCH 52/86] Task/destructure query parameters in controllers (#7495) Destructure query parameters in controllers --- .../app/activities/activities.controller.ts | 66 ++++++++++++------- .../ghostfolio/ghostfolio.controller.ts | 20 +++--- apps/api/src/app/export/export.controller.ts | 32 ++++++--- 3 files changed, 76 insertions(+), 42 deletions(-) diff --git a/apps/api/src/app/activities/activities.controller.ts b/apps/api/src/app/activities/activities.controller.ts index daade2a59..a1b559c84 100644 --- a/apps/api/src/app/activities/activities.controller.ts +++ b/apps/api/src/app/activities/activities.controller.ts @@ -62,7 +62,16 @@ export class ActivitiesController { @UseInterceptors(TransformDataSourceInRequestInterceptor) public async deleteActivities( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query() query: ActivitiesFilterDto + @Query() + { + accounts, + activityTypes, + assetClasses, + dataSource, + range, + symbol, + tags + }: ActivitiesFilterDto ): Promise { if (impersonationId) { throw new HttpException( @@ -74,25 +83,25 @@ export class ActivitiesController { let endDate: Date; let startDate: Date; - if (query.range) { + if (range) { ({ endDate, startDate } = getIntervalFromDateRange({ - dateRange: query.range + dateRange: range })); } const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts: query.accounts, - filterByAssetClasses: query.assetClasses, - filterByDataSource: query.dataSource, - filterBySymbol: query.symbol, - filterByTags: query.tags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); return this.activitiesService.deleteActivities({ endDate, filters, startDate, - types: query.activityTypes, + types: activityTypes, userId: this.request.user.id }); } @@ -125,23 +134,36 @@ export class ActivitiesController { @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getAllActivities( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query() query: GetActivitiesDto + @Query() + { + accounts, + activityTypes, + assetClasses, + dataSource, + range, + skip, + sortColumn, + sortDirection, + symbol, + tags, + take + }: GetActivitiesDto ): Promise { let endDate: Date; let startDate: Date; - if (query.range) { + if (range) { ({ endDate, startDate } = getIntervalFromDateRange({ - dateRange: query.range + dateRange: range })); } const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts: query.accounts, - filterByAssetClasses: query.assetClasses, - filterByDataSource: query.dataSource, - filterBySymbol: query.symbol, - filterByTags: query.tags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); const impersonationUserId = @@ -152,14 +174,14 @@ export class ActivitiesController { const { activities, count } = await this.activitiesService.getActivities({ endDate, filters, + skip, + sortColumn, + sortDirection, startDate, + take, userCurrency, includeDrafts: true, - skip: query.skip, - sortColumn: query.sortColumn, - sortDirection: query.sortDirection, - take: query.take, - types: query.activityTypes, + types: activityTypes, userId: impersonationUserId || this.request.user.id, withExcludedAccountsAndActivities: true }); diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts index 6e5f48d63..0cdca8110 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts @@ -90,7 +90,7 @@ export class GhostfolioController { @Version('2') public async getDividends( @Param('symbol') symbol: string, - @Query() query: GetDividendsDto + @Query() { from, granularity, to }: GetDividendsDto ): Promise { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); @@ -105,10 +105,10 @@ export class GhostfolioController { try { const dividends = await this.ghostfolioService.getDividends({ + granularity, symbol, - from: parseDate(query.from), - granularity: query.granularity, - to: parseDate(query.to) + from: parseDate(from), + to: parseDate(to) }); await this.ghostfolioService.incrementDailyRequests({ @@ -130,7 +130,7 @@ export class GhostfolioController { @Version('2') public async getHistorical( @Param('symbol') symbol: string, - @Query() query: GetHistoricalDto + @Query() { from, granularity, to }: GetHistoricalDto ): Promise { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); @@ -145,10 +145,10 @@ export class GhostfolioController { try { const historicalData = await this.ghostfolioService.getHistorical({ + granularity, symbol, - from: parseDate(query.from), - granularity: query.granularity, - to: parseDate(query.to) + from: parseDate(from), + to: parseDate(to) }); await this.ghostfolioService.incrementDailyRequests({ @@ -247,7 +247,7 @@ export class GhostfolioController { @UseGuards(AuthGuard('api-key'), HasPermissionGuard) @Version('2') public async getQuotes( - @Query() query: GetQuotesDto + @Query() { symbols }: GetQuotesDto ): Promise { const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); @@ -262,7 +262,7 @@ export class GhostfolioController { try { const quotes = await this.ghostfolioService.getQuotes({ - symbols: query.symbols + symbols }); await this.ghostfolioService.incrementDailyRequests({ diff --git a/apps/api/src/app/export/export.controller.ts b/apps/api/src/app/export/export.controller.ts index f503088d4..27218d03d 100644 --- a/apps/api/src/app/export/export.controller.ts +++ b/apps/api/src/app/export/export.controller.ts @@ -32,30 +32,42 @@ export class ExportController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async export(@Query() query: GetExportDto): Promise { + public async export( + @Query() + { + accounts, + activityIds, + activityTypes, + assetClasses, + dataSource, + range, + symbol, + tags + }: GetExportDto + ): Promise { let endDate: Date; let startDate: Date; - if (query.range) { + if (range) { ({ endDate, startDate } = getIntervalFromDateRange({ - dateRange: query.range + dateRange: range })); } const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts: query.accounts, - filterByAssetClasses: query.assetClasses, - filterByDataSource: query.dataSource, - filterBySymbol: query.symbol, - filterByTags: query.tags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); return this.exportService.export({ + activityIds, + activityTypes, endDate, filters, startDate, - activityIds: query.activityIds, - activityTypes: query.activityTypes, userId: this.request.user.id, userSettings: this.request.user.settings.settings }); From 0efadd7c8c374ee363818fa7a9c7b13f478d55f1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:36:40 +0200 Subject: [PATCH 53/86] Task/destructure query parameters in controllers (part 2) (#7505) Destructure query parameters in controllers --- .../app/activities/activities-filter.dto.ts | 30 +--- .../api/src/app/endpoints/ai/ai.controller.ts | 18 +- .../benchmarks/benchmarks.controller.ts | 37 ++-- .../get-benchmark-market-data.dto.ts | 12 ++ apps/api/src/app/portfolio/get-details.dto.ts | 12 ++ .../src/app/portfolio/get-dividends.dto.ts | 10 ++ .../api/src/app/portfolio/get-holdings.dto.ts | 14 ++ .../src/app/portfolio/get-investments.dto.ts | 10 ++ .../src/app/portfolio/get-performance.dto.ts | 12 ++ .../src/app/portfolio/portfolio.controller.ts | 159 ++++++++++-------- apps/api/src/dtos/date-range-filter.dto.ts | 16 ++ apps/api/src/dtos/filter.dto.ts | 23 +++ .../account-detail-dialog.component.ts | 3 +- libs/ui/src/lib/services/data.service.ts | 8 +- 14 files changed, 227 insertions(+), 137 deletions(-) create mode 100644 apps/api/src/app/endpoints/benchmarks/get-benchmark-market-data.dto.ts create mode 100644 apps/api/src/app/portfolio/get-details.dto.ts create mode 100644 apps/api/src/app/portfolio/get-dividends.dto.ts create mode 100644 apps/api/src/app/portfolio/get-holdings.dto.ts create mode 100644 apps/api/src/app/portfolio/get-investments.dto.ts create mode 100644 apps/api/src/app/portfolio/get-performance.dto.ts create mode 100644 apps/api/src/dtos/date-range-filter.dto.ts create mode 100644 apps/api/src/dtos/filter.dto.ts diff --git a/apps/api/src/app/activities/activities-filter.dto.ts b/apps/api/src/app/activities/activities-filter.dto.ts index e5a22c020..0c56aacc8 100644 --- a/apps/api/src/app/activities/activities-filter.dto.ts +++ b/apps/api/src/app/activities/activities-filter.dto.ts @@ -1,19 +1,13 @@ -import { DATE_RANGES } from '@ghostfolio/common/config'; +import { DATE_RANGE_PATTERN } from '@ghostfolio/api/dtos/date-range-filter.dto'; +import { FilterDto } from '@ghostfolio/api/dtos/filter.dto'; import { DateRange } from '@ghostfolio/common/types'; import { Type as ActivityType } from '@prisma/client'; import { Transform, TransformFnParams } from 'class-transformer'; -import { IsEnum, IsOptional, IsString, Matches } from 'class-validator'; +import { IsEnum, IsOptional, Matches } from 'class-validator'; import { isString } from 'lodash'; -// A named date range or a calendar year like '2024', '2023', '2022', etc. -const DATE_RANGE_PATTERN = new RegExp(`^(${DATE_RANGES.join('|')}|\\d{4})$`); - -export class ActivitiesFilterDto { - @IsOptional() - @IsString() - accounts?: string; - +export class ActivitiesFilterDto extends FilterDto { @IsEnum(ActivityType, { each: true }) @IsOptional() @Transform(({ value }: TransformFnParams) => { @@ -21,23 +15,7 @@ export class ActivitiesFilterDto { }) activityTypes?: ActivityType[]; - @IsOptional() - @IsString() - assetClasses?: string; - - @IsOptional() - @IsString() - dataSource?: string; - @IsOptional() @Matches(DATE_RANGE_PATTERN) range?: DateRange; - - @IsOptional() - @IsString() - symbol?: string; - - @IsOptional() - @IsString() - tags?: string; } diff --git a/apps/api/src/app/endpoints/ai/ai.controller.ts b/apps/api/src/app/endpoints/ai/ai.controller.ts index b1607b53b..6c8102db1 100644 --- a/apps/api/src/app/endpoints/ai/ai.controller.ts +++ b/apps/api/src/app/endpoints/ai/ai.controller.ts @@ -1,4 +1,5 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; +import { FilterDto } from '@ghostfolio/api/dtos/filter.dto'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { AiPromptResponse } from '@ghostfolio/common/interfaces'; @@ -31,18 +32,15 @@ export class AiController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async getPrompt( @Param('mode') mode: AiPromptMode, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string + @Query() + { accounts, assetClasses, dataSource, symbol, tags }: FilterDto ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); const prompt = await this.aiService.getPrompt({ diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts index 74bb6b672..53df9bd92 100644 --- a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts @@ -5,17 +5,14 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; -import { - DEFAULT_DATE_RANGE, - HEADER_KEY_IMPERSONATION -} from '@ghostfolio/common/config'; +import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; import type { AssetProfileIdentifier, BenchmarkMarketDataDetailsResponse, BenchmarkResponse } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; -import type { DateRange, RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, @@ -37,6 +34,7 @@ import { DataSource } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { BenchmarksService } from './benchmarks.service'; +import { GetBenchmarkMarketDataDto } from './get-benchmark-market-data.dto'; @Controller('benchmarks') export class BenchmarksController { @@ -121,38 +119,39 @@ export class BenchmarksController { @Param('dataSource') dataSource: DataSource, @Param('startDateString') startDateString: string, @Param('symbol') symbol: string, - @Query('range') dateRange: DateRange = DEFAULT_DATE_RANGE, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string, - @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' + @Query() + { + accounts, + assetClasses, + dataSource: filterByDataSource, + range, + symbol: filterBySymbol, + tags, + withExcludedAccounts + }: GetBenchmarkMarketDataDto ): Promise { const { endDate, startDate } = getIntervalFromDateRange({ - dateRange, + dateRange: range, startDate: new Date(startDateString) }); const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, filterByDataSource, filterBySymbol, - filterByTags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByTags: tags }); - const withExcludedAccounts = withExcludedAccountsParam === 'true'; - return this.benchmarksService.getMarketDataForUser({ dataSource, - dateRange, endDate, filters, impersonationId, startDate, symbol, withExcludedAccounts, + dateRange: range, user: this.request.user }); } diff --git a/apps/api/src/app/endpoints/benchmarks/get-benchmark-market-data.dto.ts b/apps/api/src/app/endpoints/benchmarks/get-benchmark-market-data.dto.ts new file mode 100644 index 000000000..9599ade59 --- /dev/null +++ b/apps/api/src/app/endpoints/benchmarks/get-benchmark-market-data.dto.ts @@ -0,0 +1,12 @@ +import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto'; + +import { Transform, TransformFnParams } from 'class-transformer'; +import { IsBoolean } from 'class-validator'; + +export class GetBenchmarkMarketDataDto extends DateRangeFilterDto { + @IsBoolean() + @Transform(({ value }: TransformFnParams) => { + return value === 'true'; + }) + withExcludedAccounts? = false; +} diff --git a/apps/api/src/app/portfolio/get-details.dto.ts b/apps/api/src/app/portfolio/get-details.dto.ts new file mode 100644 index 000000000..e2a13e3b6 --- /dev/null +++ b/apps/api/src/app/portfolio/get-details.dto.ts @@ -0,0 +1,12 @@ +import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto'; + +import { Transform, TransformFnParams } from 'class-transformer'; +import { IsBoolean } from 'class-validator'; + +export class GetDetailsDto extends DateRangeFilterDto { + @IsBoolean() + @Transform(({ value }: TransformFnParams) => { + return value === 'true'; + }) + withMarkets? = false; +} diff --git a/apps/api/src/app/portfolio/get-dividends.dto.ts b/apps/api/src/app/portfolio/get-dividends.dto.ts new file mode 100644 index 000000000..f1dff4a97 --- /dev/null +++ b/apps/api/src/app/portfolio/get-dividends.dto.ts @@ -0,0 +1,10 @@ +import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto'; +import { GroupBy } from '@ghostfolio/common/types'; + +import { IsIn, IsOptional } from 'class-validator'; + +export class GetDividendsDto extends DateRangeFilterDto { + @IsIn(['month', 'year'] as GroupBy[]) + @IsOptional() + groupBy?: GroupBy; +} diff --git a/apps/api/src/app/portfolio/get-holdings.dto.ts b/apps/api/src/app/portfolio/get-holdings.dto.ts new file mode 100644 index 000000000..b776bfe0d --- /dev/null +++ b/apps/api/src/app/portfolio/get-holdings.dto.ts @@ -0,0 +1,14 @@ +import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto'; +import { HoldingType } from '@ghostfolio/common/types'; + +import { IsIn, IsOptional, IsString } from 'class-validator'; + +export class GetHoldingsDto extends DateRangeFilterDto { + @IsIn(['ACTIVE', 'CLOSED'] as HoldingType[]) + @IsOptional() + holdingType?: HoldingType; + + @IsOptional() + @IsString() + query?: string; +} diff --git a/apps/api/src/app/portfolio/get-investments.dto.ts b/apps/api/src/app/portfolio/get-investments.dto.ts new file mode 100644 index 000000000..bf312a543 --- /dev/null +++ b/apps/api/src/app/portfolio/get-investments.dto.ts @@ -0,0 +1,10 @@ +import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto'; +import { GroupBy } from '@ghostfolio/common/types'; + +import { IsIn, IsOptional } from 'class-validator'; + +export class GetInvestmentsDto extends DateRangeFilterDto { + @IsIn(['month', 'year'] as GroupBy[]) + @IsOptional() + groupBy?: GroupBy; +} diff --git a/apps/api/src/app/portfolio/get-performance.dto.ts b/apps/api/src/app/portfolio/get-performance.dto.ts new file mode 100644 index 000000000..5992c2a09 --- /dev/null +++ b/apps/api/src/app/portfolio/get-performance.dto.ts @@ -0,0 +1,12 @@ +import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto'; + +import { Transform, TransformFnParams } from 'class-transformer'; +import { IsBoolean } from 'class-validator'; + +export class GetPerformanceDto extends DateRangeFilterDto { + @IsBoolean() + @Transform(({ value }: TransformFnParams) => { + return value === 'true'; + }) + withExcludedAccounts? = false; +} diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 5239de24f..f6e8648d5 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -15,7 +15,6 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { - DEFAULT_DATE_RANGE, HEADER_KEY_IMPERSONATION, UNKNOWN_KEY } from '@ghostfolio/common/config'; @@ -34,11 +33,7 @@ import { isRestrictedView, permissions } from '@ghostfolio/common/permissions'; -import type { - DateRange, - GroupBy, - RequestWithUser -} from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, @@ -60,6 +55,11 @@ import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; import { Big } from 'big.js'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; +import { GetDetailsDto } from './get-details.dto'; +import { GetDividendsDto } from './get-dividends.dto'; +import { GetHoldingsDto } from './get-holdings.dto'; +import { GetInvestmentsDto } from './get-investments.dto'; +import { GetPerformanceDto } from './get-performance.dto'; import { PortfolioService } from './portfolio.service'; import { UpdateHoldingTagsDto } from './update-holding-tags.dto'; @@ -82,16 +82,17 @@ export class PortfolioController { @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getDetails( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('range') dateRange: DateRange = DEFAULT_DATE_RANGE, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string, - @Query('withMarkets') withMarketsParam = 'false' + @Query() + { + accounts: filterByAccounts, + assetClasses: filterByAssetClasses, + dataSource: filterByDataSource, + range, + symbol: filterBySymbol, + tags: filterByTags, + withMarkets + }: GetDetailsDto ): Promise { - const withMarkets = withMarketsParam === 'true'; - let hasDetails = true; let hasError = false; @@ -118,10 +119,10 @@ export class PortfolioController { platforms, summary } = await this.portfolioService.getDetails({ - dateRange, filters, impersonationId, withMarkets, + dateRange: range, userId: this.request.user.id, withSummary: true }); @@ -326,20 +327,23 @@ export class PortfolioController { @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getDividends( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('groupBy') groupBy?: GroupBy, - @Query('range') dateRange: DateRange = DEFAULT_DATE_RANGE, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string + @Query() + { + accounts, + assetClasses, + dataSource, + groupBy, + range, + symbol, + tags + }: GetDividendsDto ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); const impersonationUserId = @@ -349,7 +353,9 @@ export class PortfolioController { const { settings } = await this.userService.user({ id: userId }); const userCurrency = settings.settings.baseCurrency; - const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); + const { endDate, startDate } = getIntervalFromDateRange({ + dateRange: range + }); const { activities } = await this.activitiesService.getActivities({ endDate, @@ -429,29 +435,32 @@ export class PortfolioController { @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getHoldings( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('holdingType') filterByHoldingType?: string, - @Query('query') filterBySearchQuery?: string, - @Query('range') dateRange: DateRange = DEFAULT_DATE_RANGE, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string + @Query() + { + accounts, + assetClasses, + dataSource, + holdingType, + query, + range, + symbol, + tags + }: GetHoldingsDto ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterByHoldingType, - filterBySearchQuery, - filterBySymbol, - filterByTags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterByHoldingType: holdingType, + filterBySearchQuery: query, + filterBySymbol: symbol, + filterByTags: tags }); const holdings = await this.portfolioService.getHoldings({ - dateRange, filters, impersonationId, + dateRange: range, userId: this.request.user.id }); @@ -463,27 +472,30 @@ export class PortfolioController { @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getInvestments( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('groupBy') groupBy?: GroupBy, - @Query('range') dateRange: DateRange = DEFAULT_DATE_RANGE, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string + @Query() + { + accounts, + assetClasses, + dataSource, + groupBy, + range, + symbol, + tags + }: GetInvestmentsDto ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); let { investments, streaks } = await this.portfolioService.getInvestments({ - dateRange, filters, groupBy, impersonationId, + dateRange: range, savingsRate: this.request.user?.settings?.settings.savingsRate, userId: this.request.user.id }); @@ -536,29 +548,30 @@ export class PortfolioController { @Version('2') public async getPerformanceV2( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, - @Query('accounts') filterByAccounts?: string, - @Query('assetClasses') filterByAssetClasses?: string, - @Query('dataSource') filterByDataSource?: string, - @Query('range') dateRange: DateRange = DEFAULT_DATE_RANGE, - @Query('symbol') filterBySymbol?: string, - @Query('tags') filterByTags?: string, - @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' + @Query() + { + accounts, + assetClasses, + dataSource, + range, + symbol, + tags, + withExcludedAccounts + }: GetPerformanceDto ): Promise { - const withExcludedAccounts = withExcludedAccountsParam === 'true'; - const filters = this.apiService.buildFiltersFromQueryParams({ - filterByAccounts, - filterByAssetClasses, - filterByDataSource, - filterBySymbol, - filterByTags + filterByAccounts: accounts, + filterByAssetClasses: assetClasses, + filterByDataSource: dataSource, + filterBySymbol: symbol, + filterByTags: tags }); const performanceInformation = await this.portfolioService.getPerformance({ - dateRange, filters, impersonationId, withExcludedAccounts, + dateRange: range, userId: this.request.user.id }); diff --git a/apps/api/src/dtos/date-range-filter.dto.ts b/apps/api/src/dtos/date-range-filter.dto.ts new file mode 100644 index 000000000..bf440ac7c --- /dev/null +++ b/apps/api/src/dtos/date-range-filter.dto.ts @@ -0,0 +1,16 @@ +import { DATE_RANGES, DEFAULT_DATE_RANGE } from '@ghostfolio/common/config'; +import { DateRange } from '@ghostfolio/common/types'; + +import { Matches } from 'class-validator'; + +import { FilterDto } from './filter.dto'; + +// A named date range or a calendar year like '2024', '2023', '2022', etc. +export const DATE_RANGE_PATTERN = new RegExp( + `^(${DATE_RANGES.join('|')}|\\d{4})$` +); + +export class DateRangeFilterDto extends FilterDto { + @Matches(DATE_RANGE_PATTERN) + range?: DateRange = DEFAULT_DATE_RANGE; +} diff --git a/apps/api/src/dtos/filter.dto.ts b/apps/api/src/dtos/filter.dto.ts new file mode 100644 index 000000000..cb26d582b --- /dev/null +++ b/apps/api/src/dtos/filter.dto.ts @@ -0,0 +1,23 @@ +import { IsOptional, IsString } from 'class-validator'; + +export class FilterDto { + @IsOptional() + @IsString() + accounts?: string; + + @IsOptional() + @IsString() + assetClasses?: string; + + @IsOptional() + @IsString() + dataSource?: string; + + @IsOptional() + @IsString() + symbol?: string; + + @IsOptional() + @IsString() + tags?: string; +} 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 fdb0ba97a..d1845222a 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 @@ -341,8 +341,7 @@ export class GfAccountDetailDialogComponent implements OnInit { } ], range: DEFAULT_DATE_RANGE, - withExcludedAccounts: true, - withItems: true + withExcludedAccounts: true }) .pipe(takeUntilDestroyed(this.destroyRef)) }).subscribe({ diff --git a/libs/ui/src/lib/services/data.service.ts b/libs/ui/src/lib/services/data.service.ts index 7ccd9d1d9..7081f9b2c 100644 --- a/libs/ui/src/lib/services/data.service.ts +++ b/libs/ui/src/lib/services/data.service.ts @@ -731,13 +731,11 @@ export class DataService { public fetchPortfolioPerformance({ filters, range, - withExcludedAccounts = false, - withItems = false + withExcludedAccounts = false }: { filters?: Filter[]; range: DateRange; withExcludedAccounts?: boolean; - withItems?: boolean; }): Observable { let params = this.buildFiltersAsQueryParams({ filters }); params = params.append('range', range); @@ -746,10 +744,6 @@ export class DataService { params = params.append('withExcludedAccounts', withExcludedAccounts); } - if (withItems) { - params = params.append('withItems', withItems); - } - return this.http .get(`/api/v2/portfolio/performance`, { params From 3eaba49f19859d899b133407e10ea6a46a183539 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 3 Aug 2026 19:48:49 +0200 Subject: [PATCH 54/86] Task/improve handling of encoded data source in user settings (#7521) Improve handling of encoded data source in user settings --- apps/api/src/app/user/user.controller.ts | 10 ++++++++++ apps/api/src/app/user/user.module.ts | 4 +++- .../transform-data-source-in-response.interceptor.ts | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts index 7a1fc71dc..2b679f34c 100644 --- a/apps/api/src/app/user/user.controller.ts +++ b/apps/api/src/app/user/user.controller.ts @@ -1,7 +1,9 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { CustomThrottlerGuard } from '@ghostfolio/api/guards/custom-throttler.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { decodeDataSource } from '@ghostfolio/api/helper/data-source.helper'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; +import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; @@ -119,6 +121,7 @@ export class UserController { @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) + @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getUser( @Headers('accept-language') acceptLanguage: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string @@ -165,6 +168,7 @@ export class UserController { @Put('setting') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseInterceptors(TransformDataSourceInResponseInterceptor) public async updateUserSetting(@Body() data: UpdateUserSettingDto) { if ( size(data) === 1 && @@ -192,6 +196,12 @@ export class UserController { data ); + if (userSettings['filters.dataSource']) { + userSettings['filters.dataSource'] = decodeDataSource( + userSettings['filters.dataSource'] + ); + } + for (const key in userSettings) { if (userSettings[key] === false || userSettings[key] === null) { delete userSettings[key]; diff --git a/apps/api/src/app/user/user.module.ts b/apps/api/src/app/user/user.module.ts index 3f4e898fc..156630964 100644 --- a/apps/api/src/app/user/user.module.ts +++ b/apps/api/src/app/user/user.module.ts @@ -1,6 +1,7 @@ import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module'; import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module'; +import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { I18nModule } from '@ghostfolio/api/services/i18n/i18n.module'; import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; @@ -30,7 +31,8 @@ import { UserService } from './user.service'; PropertyModule, RedactValuesInResponseModule, SubscriptionModule, - TagModule + TagModule, + TransformDataSourceInResponseModule ], providers: [UserService] }) diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index 6b38b2d54..81aabf4ae 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -78,6 +78,7 @@ export class TransformDataSourceInResponseInterceptor< valueMap, object: data, paths: [ + '["filters.dataSource"]', 'activities[*].assetProfile.dataSource', 'activities[*].dataSource', 'assetProfile.dataSource', @@ -88,6 +89,7 @@ export class TransformDataSourceInResponseInterceptor< 'holdings[*].assetProfile.dataSource', 'holdings[*].dataSource', 'items[*].dataSource', + 'settings["filters.dataSource"]', 'watchlist[*].dataSource' ] }); From 75e3d032abd554a84954a7ba68d2dfc02516b69c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 3 Aug 2026 19:56:36 +0200 Subject: [PATCH 55/86] Feature/stock splits setup (part 2) (#7523) Improve stock splits setup --- .../asset-profiles.controller.ts | 2 + .../asset-profiles/asset-profiles.module.ts | 2 + .../asset-profiles/asset-profiles.service.ts | 12 +++- .../asset-profile-dialog.html | 59 ++++++++----------- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts index 6521665e1..5ffb756a0 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts @@ -142,6 +142,8 @@ export class AssetProfilesController { }); return this.assetProfilesService.createSplit({ + dataSource, + symbol, symbolProfileId, date: parseISO(data.date), denominator: data.denominator, diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts index e3906be9f..9df342f5f 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.module.ts @@ -8,6 +8,7 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data- import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; @@ -23,6 +24,7 @@ import { AssetProfilesService } from './asset-profiles.service'; ApiModule, AssetProfileSplitModule, BenchmarkModule, + DataGatheringQueueModule, DataProviderModule, ExchangeRateDataModule, MarketDataModule, diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts index 7d75fc40b..0d50e2223 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.service.ts @@ -5,6 +5,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { UpdateAssetProfileDataDto } from '@ghostfolio/common/dtos'; import { @@ -33,6 +34,7 @@ export class AssetProfilesService { private readonly activitiesService: ActivitiesService, private readonly assetProfileSplitService: AssetProfileSplitService, private readonly benchmarkService: BenchmarkService, + private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, @@ -41,22 +43,28 @@ export class AssetProfilesService { ) {} public async createSplit({ + dataSource, date, denominator, numerator, + symbol, symbolProfileId }: { date: Date; denominator: number; numerator: number; symbolProfileId: string; - }) { - return this.assetProfileSplitService.upsert({ + } & AssetProfileIdentifier) { + const assetProfileSplit = await this.assetProfileSplitService.upsert({ date, denominator, numerator, symbolProfileId }); + + await this.dataGatheringService.gatherSymbol({ dataSource, symbol }); + + return assetProfileSplit; } public async deleteSplit({ diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index f5df34ab4..f80cec842 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -514,10 +514,6 @@
-

- Splits are stored for this asset profile, but are not applied - to the portfolio calculation yet. -

@if (splits.length > 0) { @@ -580,38 +576,33 @@ - - Shares After - - Numerator, - e.g. 4 for a 4:1 split or 1 for a 1:10 reverse - split + - - - Shares Before - - Denominator, - e.g. 1 for a 4:1 split or 10 for a 1:10 reverse - splitShares After + + +
:
+ - + Shares Before + +
+
From 37cae1f3d812afb67d6b128cf5ca9b8f4d0c02f3 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:12:13 +0200 Subject: [PATCH 57/86] Bugfix/loading indicators in user detail dialog of admin control (#7520) * Fix loading indicators * Update changelog --- CHANGELOG.md | 4 +++ .../user-detail-dialog.component.ts | 7 +++++ .../user-detail-dialog.html | 28 ++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38e3855f2..123ef1f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added the database model and endpoints to manage the stock splits of an asset profile (experimental) +### Fixed + +- Fixed the loading state in the user detail dialog of the admin control panel’s users section + ## 3.40.0 - 2026-08-02 ### Changed diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts index 9e341037a..3aec4d42c 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts @@ -56,14 +56,18 @@ export class GfUserDetailDialogComponent implements OnInit { protected readonly baseCurrency: string; protected readonly canDeleteUser = canDeleteUser; protected readonly getCountryName = getCountryName; + protected isLoading = true; + protected readonly subscriptionsDataSource = new MatTableDataSource(); + protected readonly subscriptionsDisplayedColumns = [ 'createdAt', 'type', 'price', 'expiresAt' ]; + protected user: AdminUserResponse; protected readonly data = inject(MAT_DIALOG_DATA); @@ -72,6 +76,7 @@ export class GfUserDetailDialogComponent implements OnInit { private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly dataService = inject(DataService); private readonly destroyRef = inject(DestroyRef); + private readonly dialogRef = inject>( MatDialogRef @@ -101,6 +106,8 @@ export class GfUserDetailDialogComponent implements OnInit { this.subscriptionsDataSource.data = this.user.subscriptions ?? []; + this.isLoading = false; + this.changeDetectorRef.markForCheck(); }); } diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html index e2cdb66a5..b77e0043e 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -36,12 +36,14 @@ i18n size="medium" [enableCopyToClipboardButton]="true" - [value]="user?.id" + [value]="isLoading ? undefined : user.id" >User ID
- Role + Role
@@ -52,7 +54,7 @@ size="medium" [isDate]="true" [locale]="data.locale" - [value]="user?.createdAt" + [value]="isLoading ? undefined : user.createdAt" >Registration Date @@ -61,7 +63,7 @@ i18n size="medium" [locale]="data.locale" - [value]="user?.provider" + [value]="isLoading ? undefined : user.provider" >Authentication @@ -74,7 +76,9 @@ i18n size="medium" [locale]="data.locale" - [value]="user?.subscription ? 'Premium' : 'Basic'" + [value]=" + isLoading ? undefined : user.subscription ? 'Premium' : 'Basic' + " >Membership @@ -83,7 +87,11 @@ i18n size="medium" [value]=" - user?.country ? getCountryName({ code: user.country }) : '-' + isLoading + ? undefined + : user.country + ? getCountryName({ code: user.country }) + : '-' " >Country @@ -97,7 +105,7 @@ i18n size="medium" [locale]="data.locale" - [value]="user?.accountCount" + [value]="isLoading ? undefined : user.accountCount" >Accounts @@ -106,7 +114,7 @@ i18n size="medium" [locale]="data.locale" - [value]="user?.activityCount" + [value]="isLoading ? undefined : user.activityCount" >Activities @@ -120,7 +128,7 @@ size="medium" [locale]="data.locale" [precision]="0" - [value]="user?.engagement" + [value]="isLoading ? undefined : user.engagement" >Engagement per Day @@ -129,7 +137,7 @@ i18n size="medium" [locale]="data.locale" - [value]="user?.dailyApiRequests" + [value]="isLoading ? undefined : user.dailyApiRequests" >API Requests Today From 132f8670b971dcc381555a10e1860ba06c221638 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:41:34 +0200 Subject: [PATCH 58/86] Task/improve usability in admin control panel by eliminating page reloads (#7518) * Improve usability by eliminating page reloads * Update changelog --- CHANGELOG.md | 7 +++ .../admin-market-data.component.ts | 62 ++++++++++++++----- .../admin-market-data.service.ts | 17 +++-- .../asset-profile-dialog.component.ts | 9 ++- .../admin-overview.component.ts | 41 +++++++++--- .../admin-overview/admin-overview.html | 15 +++-- .../user-account-membership.component.ts | 23 ++----- 7 files changed, 120 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 123ef1f94..a916f8643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added the database model and endpoints to manage the stock splits of an asset profile (experimental) +### Changed + +- Improved the usability of the admin control panel by eliminating the page reload on changing a setting +- Improved the usability of the admin control panel by eliminating the page reload on deleting an asset profile +- Improved the usability of the admin control panel by eliminating the page reload on flushing the cache +- Improved the usability of the admin control panel by eliminating the page reload on gathering historical market data + ### Fixed - Fixed the loading state in the user detail dialog of the admin control panel’s users section diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts index b29ccc7d7..8592070ee 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts @@ -43,6 +43,7 @@ import { MatPaginatorModule, PageEvent } from '@angular/material/paginator'; +import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSort, MatSortModule, @@ -64,6 +65,7 @@ import { ellipsisVertical, trashOutline } from 'ionicons/icons'; +import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; @@ -88,6 +90,7 @@ import { CreateAssetProfileDialogParams } from './create-asset-profile-dialog/in MatCheckboxModule, MatMenuModule, MatPaginatorModule, + MatSnackBarModule, MatSortModule, MatTableModule, NgxSkeletonLoaderModule, @@ -177,6 +180,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { private readonly dialog = inject(MatDialog); private readonly route = inject(ActivatedRoute); private readonly router = inject(Router); + private readonly snackBar = inject(MatSnackBar); private readonly userService = inject(UserService); public constructor() { @@ -239,7 +243,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { .subscribe((filters) => { this.activeFilters = filters; - this.loadData(); + this.reloadData({ pageIndex: 0 }); }); addIcons({ @@ -285,15 +289,25 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { dataSource, symbol }: AssetProfileIdentifier) { - this.adminMarketDataService.deleteAssetProfile({ dataSource, symbol }); + this.adminMarketDataService + .deleteAssetProfile({ dataSource, symbol }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.reloadData(); + }); } protected onDeleteAssetProfiles() { - this.adminMarketDataService.deleteAssetProfiles( - this.selection.selected.map(({ dataSource, symbol }) => { - return { dataSource, symbol }; - }) - ); + this.adminMarketDataService + .deleteAssetProfiles( + this.selection.selected.map(({ dataSource, symbol }) => { + return { dataSource, symbol }; + }) + ) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.reloadData(); + }); } protected onGatherMax() { @@ -301,9 +315,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { .gatherMax() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + this.notifyDataGatheringHasBeenStarted(); }); } @@ -311,7 +323,9 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { this.adminService .gatherProfileData() .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(); + .subscribe(() => { + this.notifyDataGatheringHasBeenStarted(); + }); } protected onGatherRecentMarketData() { @@ -319,9 +333,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { .gatherRecentMarketData() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + this.notifyDataGatheringHasBeenStarted(); }); } @@ -396,6 +408,16 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { }); } + private notifyDataGatheringHasBeenStarted() { + this.snackBar.open( + '✅ ' + $localize`Data gathering has been started.`, + undefined, + { + duration: ms('3 seconds') + } + ); + } + private openAssetProfileDialog({ dataSource, symbol @@ -431,6 +453,8 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { if (newAssetProfileIdentifier) { this.onOpenAssetProfileDialog(newAssetProfileIdentifier); } else { + this.reloadData(); + this.router.navigate(['.'], { relativeTo: this.route }); } }); @@ -483,4 +507,14 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { }); }); } + + private reloadData({ + pageIndex = this.paginator().pageIndex + }: { pageIndex?: number } = {}) { + this.loadData({ + pageIndex, + sortColumn: this.sort().active, + sortDirection: this.sort().direction + }); + } } diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts index 28c8c2d9f..c4d45b7f0 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts @@ -4,7 +4,7 @@ import { NotificationService } from '@ghostfolio/ui/notifications'; import { AdminService } from '@ghostfolio/ui/services'; import { Injectable } from '@angular/core'; -import { EMPTY, catchError, finalize, forkJoin } from 'rxjs'; +import { EMPTY, Subject, catchError, finalize, forkJoin } from 'rxjs'; @Injectable() export class AdminMarketDataService { @@ -14,25 +14,29 @@ export class AdminMarketDataService { ) {} public deleteAssetProfile({ dataSource, symbol }: AssetProfileIdentifier) { + const assetProfileDeleted = new Subject(); + this.notificationService.confirm({ confirmFn: () => { this.adminService .deleteProfileData({ dataSource, symbol }) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + assetProfileDeleted.next(); + assetProfileDeleted.complete(); }); }, confirmType: ConfirmationDialogType.Warn, title: $localize`Do you really want to delete this asset profile?` }); + + return assetProfileDeleted.asObservable(); } public deleteAssetProfiles( aAssetProfileIdentifiers: AssetProfileIdentifier[] ) { const assetProfileCount = aAssetProfileIdentifiers.length; + const assetProfilesDeleted = new Subject(); this.notificationService.confirm({ confirmFn: () => { @@ -55,7 +59,8 @@ export class AdminMarketDataService { return EMPTY; }), finalize(() => { - window.location.reload(); + assetProfilesDeleted.next(); + assetProfilesDeleted.complete(); }) ) .subscribe(); @@ -66,5 +71,7 @@ export class AdminMarketDataService { ? $localize`Do you really want to delete this asset profile?` : $localize`Do you really want to delete these ${assetProfileCount}:count: asset profiles?` }); + + return assetProfilesDeleted.asObservable(); } } diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index f0e8eaf17..aa61845f4 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -531,9 +531,12 @@ export class GfAssetProfileDialogComponent implements OnInit { dataSource, symbol }: AssetProfileIdentifier) { - this.adminMarketDataService.deleteAssetProfile({ dataSource, symbol }); - - this.dialogRef.close(); + this.adminMarketDataService + .deleteAssetProfile({ dataSource, symbol }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.dialogRef.close(); + }); } protected onGatherProfileDataBySymbol({ diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index 0bed8111f..733200c91 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -64,6 +64,7 @@ import { } from 'ionicons/icons'; import ms, { StringValue } from 'ms'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { catchError, of, switchMap } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -105,6 +106,8 @@ export class GfAdminOverviewComponent implements OnInit { protected readonly info: InfoItem; protected isDataGatheringEnabled: boolean; protected isLoading = false; + protected isReadOnlyMode: boolean; + protected isUserSignupEnabled: boolean; protected readonly permissions = permissions; protected systemMessage: SystemMessage; protected userCount: number; @@ -179,6 +182,8 @@ export class GfAdminOverviewComponent implements OnInit { } public ngOnInit() { + this.isLoading = true; + this.fetchAdminData(); } @@ -270,9 +275,15 @@ export class GfAdminOverviewComponent implements OnInit { .flush() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + this.dataService.updateInfo(); + + this.snackBar.open( + '✅ ' + $localize`Cache has been flushed.`, + undefined, + { + duration: ms('3 seconds') + } + ); }); }, confirmType: ConfirmationDialogType.Warn, @@ -330,8 +341,6 @@ export class GfAdminOverviewComponent implements OnInit { } private fetchAdminData() { - this.isLoading = true; - this.adminService .fetchAdminData() .pipe(takeUntilDestroyed(this.destroyRef)) @@ -344,6 +353,11 @@ export class GfAdminOverviewComponent implements OnInit { this.isDataGatheringEnabled = settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false ? false : true; + this.isReadOnlyMode = settings[PROPERTY_IS_READ_ONLY_MODE] === true; + + this.isUserSignupEnabled = + settings[PROPERTY_IS_USER_SIGNUP_ENABLED] === false ? false : true; + this.systemMessage = settings[PROPERTY_SYSTEM_MESSAGE] as SystemMessage; this.userCount = userCount; this.version = version; @@ -372,11 +386,20 @@ export class GfAdminOverviewComponent implements OnInit { .putAdminSetting(key, { value: value || value === false ? JSON.stringify(value) : undefined }) - .pipe(takeUntilDestroyed(this.destroyRef)) + .pipe( + switchMap(() => { + return this.userService.get(true); + }), + catchError(() => { + // Refresh anyway to reflect the actual state of the settings + return of(undefined); + }), + takeUntilDestroyed(this.destroyRef) + ) .subscribe(() => { - setTimeout(() => { - window.location.reload(); - }, 300); + this.dataService.updateInfo(); + + this.fetchAdminData(); }); } diff --git a/apps/client/src/app/components/admin-overview/admin-overview.html b/apps/client/src/app/components/admin-overview/admin-overview.html index 7e05600a6..b919f085f 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -52,9 +52,8 @@ @@ -66,7 +65,8 @@ @@ -79,6 +79,7 @@ color="primary" hideIcon="true" [checked]="isDataGatheringEnabled" + [disabled]="isLoading" (change)="onEnableDataGatheringChange($event)" /> @@ -89,7 +90,9 @@
@if (systemMessage) {
-
{{ systemMessage | json }}
+
+ {{ systemMessage | json }} +
} - @if (!info?.systemMessage) { + @if (!systemMessage) {
-
+
+ @if (hasHoldingsBreakdown) { + + + + } Holdings @if ( !hasImpersonationId && @@ -192,7 +207,7 @@ />
- @if (isLoading || summary?.emergencyFund?.assets > 0) { + @if (hasHoldingsBreakdown && isHoldingsExpanded) {
Investments
@@ -223,7 +238,22 @@
}
-
+
+ @if (hasCashBreakdown) { + + + + } Cash @if ( !hasImpersonationId && @@ -251,7 +281,7 @@ />
- @if (isLoading || summary?.emergencyFund?.cash > 0) { + @if (hasCashBreakdown && isCashExpanded) {
Buying Power
diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.scss b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.scss index 6feaa22d1..534976f11 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.scss +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.scss @@ -1,6 +1,19 @@ :host { display: block; + .caret-container { + width: 1rem; + + .caret { + font-size: 0.7rem; + transition: transform 150ms ease-in-out; + + &.caret-expanded { + transform: rotate(90deg); + } + } + } + .indent-1 { margin-left: 1rem; } diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts index eaf71210f..eac5ef9a6 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts @@ -18,6 +18,7 @@ import { IonIcon } from '@ionic/angular/standalone'; import { formatDistanceToNow } from 'date-fns'; import { addIcons } from 'ionicons'; import { + caretForwardOutline, ellipsisHorizontalCircleOutline, informationCircleOutline } from 'ionicons/icons'; @@ -47,13 +48,19 @@ export class GfPortfolioSummaryComponent implements OnChanges { 'BUY_AND_SELL_ACTIVITIES_TOOLTIP' ); + protected isCashExpanded = false; + protected isHoldingsExpanded = false; protected precision = 2; protected timeInMarket: string | undefined; private readonly notificationService = inject(NotificationService); public constructor() { - addIcons({ ellipsisHorizontalCircleOutline, informationCircleOutline }); + addIcons({ + caretForwardOutline, + ellipsisHorizontalCircleOutline, + informationCircleOutline + }); } protected get cashPercentage() { @@ -77,6 +84,14 @@ export class GfPortfolioSummaryComponent implements OnChanges { : 0; } + protected get hasCashBreakdown() { + return !this.isLoading && this.summary?.emergencyFund?.cash > 0; + } + + protected get hasHoldingsBreakdown() { + return !this.isLoading && this.summary?.emergencyFund?.assets > 0; + } + protected get holdingsInBaseCurrency() { if ( !isNumber(this.summary?.totalAssetsInBaseCurrency) || @@ -145,4 +160,12 @@ export class GfPortfolioSummaryComponent implements OnChanges { title: $localize`Please set the amount of your emergency fund.` }); } + + protected onToggleCash() { + this.isCashExpanded = !this.isCashExpanded; + } + + protected onToggleHoldings() { + this.isHoldingsExpanded = !this.isHoldingsExpanded; + } } From 9f5c231a70d538878ede77df491a3fe98c7b91e0 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 4 Aug 2026 20:38:37 +0200 Subject: [PATCH 69/86] Release 3.42.0 (#7539) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8109d54f7..0b5d73495 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 3.42.0 - 2026-08-04 ### Changed diff --git a/package-lock.json b/package-lock.json index 51ee52ea1..06b0efda2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.41.0", + "version": "3.42.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.41.0", + "version": "3.42.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 61bf1c0d4..4bbda525e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.41.0", + "version": "3.42.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 5bbdf52e191dc6ff1df3dab56238db121f83de27 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 4 Aug 2026 20:57:02 +0200 Subject: [PATCH 70/86] Feature/add platform logo to account selector in create or update activity dialog (#7524) * Add platform logo to account selector * Update changelog --- CHANGELOG.md | 6 ++++++ apps/api/src/app/user/user.service.ts | 1 + .../create-or-update-activity-dialog.component.ts | 6 ++++++ .../create-or-update-activity-dialog.html | 13 +++++++++++++ .../interfaces/interfaces.ts | 5 ++--- 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b5d73495..fb6b3ef37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added the platform logo to the account selector in the create or update activity dialog + ## 3.42.0 - 2026-08-04 ### Changed diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 10e9c5240..8fb11ad34 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -136,6 +136,7 @@ export class UserService { where: { granteeUserId: id } }), this.prismaService.account.findMany({ + include: { platform: true }, orderBy: { name: 'asc' }, diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index 3b80d2825..07f596711 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -121,6 +121,12 @@ export class GfCreateOrUpdateActivityDialogComponent { addIcons({ calendarClearOutline, refreshOutline }); } + protected get selectedAccount() { + return this.data.accounts.find(({ id }) => { + return id === this.activityForm.get('accountId')?.value; + }); + } + public ngOnInit() { this.currencyOfAssetProfile = this.data.activity?.assetProfile?.currency; this.hasPermissionToCreateOwnTag = hasPermission( diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html index b5dbf4669..b3c708167 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -85,6 +85,19 @@ > Account + +
+ @if (selectedAccount?.platform?.url) { + + } + {{ selectedAccount?.name }} +
+
+ @for (account of data.accounts; track account) { diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/interfaces/interfaces.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/interfaces/interfaces.ts index a3d58f8eb..7faed5312 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/interfaces/interfaces.ts @@ -1,9 +1,8 @@ import { Activity, User } from '@ghostfolio/common/interfaces'; - -import { Account } from '@prisma/client'; +import { AccountWithPlatform } from '@ghostfolio/common/types'; export interface CreateOrUpdateActivityDialogParams { - accounts: Account[]; + accounts: AccountWithPlatform[]; activity: Partial> & { assetProfile: Activity['assetProfile'] | null; id: string | null; From b812bc74219bf96c10000b6a15bb3a6f79e5c368 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 5 Aug 2026 07:34:21 +0200 Subject: [PATCH 71/86] Task/guard system tags in admin control panel (#7532) * Guard system tags against deletion and renaming * Update changelog --- CHANGELOG.md | 4 ++++ apps/api/src/app/endpoints/tags/tags.controller.ts | 5 +++-- .../components/admin-tag/admin-tag.component.html | 12 ++++++++++-- .../app/components/admin-tag/admin-tag.component.ts | 9 +++++++-- libs/common/src/lib/config.ts | 8 +++++++- libs/common/src/lib/helper.ts | 9 ++++++++- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb6b3ef37..426cca929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added the platform logo to the account selector in the create or update activity dialog +### Changed + +- Guarded the system tags against deletion and renaming in the tag management of the admin control panel + ## 3.42.0 - 2026-08-04 ### Changed diff --git a/apps/api/src/app/endpoints/tags/tags.controller.ts b/apps/api/src/app/endpoints/tags/tags.controller.ts index 21e29c6ab..cd043b593 100644 --- a/apps/api/src/app/endpoints/tags/tags.controller.ts +++ b/apps/api/src/app/endpoints/tags/tags.controller.ts @@ -2,6 +2,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { CreateTagDto, UpdateTagDto } from '@ghostfolio/common/dtos'; +import { isSystemTag } from '@ghostfolio/common/helper'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { RequestWithUser } from '@ghostfolio/common/types'; @@ -69,7 +70,7 @@ export class TagsController { id }); - if (!originalTag) { + if (!originalTag || isSystemTag(originalTag)) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN @@ -94,7 +95,7 @@ export class TagsController { id }); - if (!originalTag) { + if (!originalTag || isSystemTag(originalTag)) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.html b/apps/client/src/app/components/admin-tag/admin-tag.component.html index 2edad000d..c7cbe37c0 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.html +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -83,7 +83,11 @@ -
diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index 9394d7624..520986c89 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2,7 +2,11 @@
Time in Market
- +
@@ -46,10 +51,11 @@
@@ -62,14 +68,11 @@ @@ -79,12 +82,11 @@ @@ -97,10 +99,11 @@ @@ -113,12 +116,11 @@ @@ -136,13 +138,10 @@ class="justify-content-end" position="end" [colorizeSign]="true" + [isLoading]="isLoading" [isPercent]="true" [locale]="locale" - [value]=" - isLoading - ? undefined - : summary?.netPerformancePercentageWithCurrencyEffect - " + [value]="summary?.netPerformancePercentageWithCurrencyEffect" /> @@ -156,10 +155,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.totalAssetsInBaseCurrency" + [value]="summary?.totalAssetsInBaseCurrency" /> @@ -188,10 +188,11 @@ ) { } @@ -200,10 +201,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : holdingsInBaseCurrency" + [value]="holdingsInBaseCurrency" /> @@ -215,10 +217,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : investmentsInBaseCurrency" + [value]="investmentsInBaseCurrency" /> @@ -229,10 +232,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.emergencyFund?.assets" + [value]="summary?.emergencyFund?.assets" /> @@ -262,10 +266,11 @@ ) { } @@ -274,10 +279,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.totalCashInBaseCurrency" + [value]="summary?.totalCashInBaseCurrency" /> @@ -289,10 +295,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.cash" + [value]="summary?.cash" /> @@ -303,10 +310,11 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoading" [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.emergencyFund?.cash" + [value]="summary?.emergencyFund?.cash" /> @@ -321,20 +329,22 @@ ) { }
@@ -353,10 +363,11 @@ @@ -369,10 +380,11 @@ @@ -385,13 +397,10 @@ class="justify-content-end" position="end" [colorizeSign]="true" + [isLoading]="isLoading" [isPercent]="true" [locale]="locale" - [value]=" - isLoading - ? undefined - : summary?.annualizedPerformancePercentWithCurrencyEffect - " + [value]="summary?.annualizedPerformancePercentWithCurrencyEffect" /> @@ -408,10 +417,11 @@ ) { } @@ -443,10 +453,11 @@ @@ -456,10 +467,11 @@ @@ -469,10 +481,11 @@ diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index 0a049a7ae..b48adf59d 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -87,6 +87,7 @@ export class GfUserAccountSettingsComponent implements OnInit { protected hasPermissionToUpdateUserSettings: boolean; protected isAccessTokenHidden = true; protected readonly isFingerprintSupported = this.doesBrowserSupportAuthn(); + protected isLoading = true; protected isWebAuthnEnabled: boolean; protected readonly language = document.documentElement.lang; protected locales = [ @@ -178,6 +179,8 @@ export class GfUserAccountSettingsComponent implements OnInit { this.locales = Array.from(new Set(this.locales)).sort(); + this.isLoading = false; + this.changeDetectorRef.markForCheck(); } }); diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.html b/apps/client/src/app/components/user-account-settings/user-account-settings.html index e77a89b24..57d3b54d7 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.html +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -273,6 +273,7 @@ diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html index b77e0043e..efc4fe5b4 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -36,12 +36,17 @@ i18n size="medium" [enableCopyToClipboardButton]="true" - [value]="isLoading ? undefined : user.id" + [isLoading]="isLoading" + [value]="user?.id" >User ID
- Role
@@ -53,8 +58,9 @@ i18n size="medium" [isDate]="true" + [isLoading]="isLoading" [locale]="data.locale" - [value]="isLoading ? undefined : user.createdAt" + [value]="user?.createdAt" >Registration Date
@@ -62,8 +68,9 @@ Authentication @@ -75,10 +82,9 @@ Membership @@ -86,12 +92,9 @@ Country @@ -104,8 +107,9 @@ Accounts @@ -113,8 +117,9 @@ Activities @@ -126,9 +131,10 @@ Engagement per Day @@ -136,8 +142,9 @@ API Requests Today diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html index d5c765958..902d04cde 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html @@ -14,12 +14,9 @@ @@ -213,6 +210,7 @@ Developed MarketsEmerging MarketsOther Markets
No data available
Total amount
@@ -104,14 +101,11 @@ size="large" [colorizeSign]="true" [isCurrency]="true" + [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" [precision]="precision" [unit]="user?.settings?.baseCurrency" - [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformanceWithCurrencyEffect - " + [value]="performance?.netPerformanceWithCurrencyEffect" >Change with currency effect
@@ -124,13 +118,10 @@ i18n size="large" [colorizeSign]="true" + [isLoading]="isLoadingInvestmentChart" [isPercent]="true" [locale]="user?.settings?.locale" - [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformancePercentageWithCurrencyEffect - " + [value]="performance?.netPerformancePercentageWithCurrencyEffect" >Performance with currency effect
@@ -173,13 +164,10 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" [unit]="user?.settings?.baseCurrency" - [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformance - " + [value]="performance?.netPerformance" /> @@ -192,13 +180,10 @@ class="justify-content-end" position="end" [colorizeSign]="true" + [isLoading]="isLoadingInvestmentChart" [isPercent]="true" [locale]="user?.settings?.locale" - [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformancePercentage - " + [value]="performance?.netPerformancePercentage" /> @@ -216,15 +201,14 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" [unit]="user?.settings?.baseCurrency" [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformance === null - ? null - : performance?.netPerformanceWithCurrencyEffect - - performance?.netPerformance + performance?.netPerformance === null + ? null + : performance?.netPerformanceWithCurrencyEffect - + performance?.netPerformance " /> @@ -238,15 +222,14 @@ class="justify-content-end" position="end" [colorizeSign]="true" + [isLoading]="isLoadingInvestmentChart" [isPercent]="true" [locale]="user?.settings?.locale" [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformancePercentage === null - ? null - : performance?.netPerformancePercentageWithCurrencyEffect - - performance?.netPerformancePercentage + performance?.netPerformancePercentage === null + ? null + : performance?.netPerformancePercentageWithCurrencyEffect - + performance?.netPerformancePercentage " /> @@ -261,13 +244,10 @@ class="justify-content-end" position="end" [isCurrency]="true" + [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" [unit]="user?.settings?.baseCurrency" - [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformanceWithCurrencyEffect - " + [value]="performance?.netPerformanceWithCurrencyEffect" /> @@ -280,12 +260,11 @@ class="justify-content-end" position="end" [colorizeSign]="true" + [isLoading]="isLoadingInvestmentChart" [isPercent]="true" [locale]="user?.settings?.locale" [value]=" - isLoadingInvestmentChart - ? undefined - : performance?.netPerformancePercentageWithCurrencyEffect + performance?.netPerformancePercentageWithCurrencyEffect " /> diff --git a/apps/client/src/app/pages/public/public-page.component.ts b/apps/client/src/app/pages/public/public-page.component.ts index 3b149cd08..e354f8a1b 100644 --- a/apps/client/src/app/pages/public/public-page.component.ts +++ b/apps/client/src/app/pages/public/public-page.component.ts @@ -69,6 +69,7 @@ export class GfPublicPageComponent implements OnInit { protected hasPermissionForSubscription: boolean; protected holdings: PublicPortfolioResponse['holdings'][string][]; protected info: InfoItem; + protected isLoading = true; protected latestActivitiesDataSource: MatTableDataSource< PublicPortfolioResponse['latestActivities'][0] >; @@ -138,6 +139,8 @@ export class GfPublicPageComponent implements OnInit { this.publicPortfolioDetails.latestActivities ); + this.isLoading = false; + this.changeDetectorRef.markForCheck(); }); } diff --git a/apps/client/src/app/pages/public/public-page.html b/apps/client/src/app/pages/public/public-page.html index 57bc1e95f..e0e855585 100644 --- a/apps/client/src/app/pages/public/public-page.html +++ b/apps/client/src/app/pages/public/public-page.html @@ -15,11 +15,11 @@ i18n size="large" [colorizeSign]="true" + [isLoading]="isLoading" [isPercent]="true" [precision]="2" [value]=" - publicPortfolioDetails?.performance?.['1d']?.relativeChange ?? - undefined + publicPortfolioDetails?.performance?.['1d']?.relativeChange " >Today
@@ -33,11 +33,11 @@ i18n size="large" [colorizeSign]="true" + [isLoading]="isLoading" [isPercent]="true" [precision]="2" [value]=" - publicPortfolioDetails?.performance?.['ytd']?.relativeChange ?? - undefined + publicPortfolioDetails?.performance?.['ytd']?.relativeChange " >This year
@@ -51,11 +51,11 @@ i18n size="large" [colorizeSign]="true" + [isLoading]="isLoading" [isPercent]="true" [precision]="2" [value]=" - publicPortfolioDetails?.performance?.['max']?.relativeChange ?? - undefined + publicPortfolioDetails?.performance?.['max']?.relativeChange " >From the beginning
diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index ffcc77832..bf7fb2caf 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -210,8 +210,9 @@ @@ -234,8 +235,9 @@
@@ -258,8 +260,9 @@
@@ -282,8 +285,9 @@
@@ -305,8 +309,9 @@
@@ -337,8 +342,9 @@
diff --git a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts index 0c75b5954..8a7e13156 100644 --- a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts +++ b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts @@ -46,6 +46,7 @@ import { BenchmarkDetailDialogParams } from './interfaces/interfaces'; export class GfBenchmarkDetailDialogComponent implements OnInit { public assetProfile: AdminMarketDataDetails['assetProfile']; public historicalDataItems: LineChartItem[]; + public isLoading = true; public value: number; public constructor( @@ -79,6 +80,8 @@ export class GfBenchmarkDetailDialogComponent implements OnInit { } ); + this.isLoading = false; + this.changeDetectorRef.markForCheck(); }); } diff --git a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.html b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.html index a8cf3730c..3ff7f03ab 100644 --- a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.html +++ b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.html @@ -11,6 +11,7 @@
@@ -105,8 +106,9 @@
@@ -125,9 +127,10 @@
@@ -147,10 +150,9 @@ @@ -170,13 +172,10 @@
diff --git a/libs/ui/src/lib/value/value.component.html b/libs/ui/src/lib/value/value.component.html index 14ac7154a..3ab711f7e 100644 --- a/libs/ui/src/lib/value/value.component.html +++ b/libs/ui/src/lib/value/value.component.html @@ -27,7 +27,20 @@ } - @if (value || value === 0 || value === null) { + + @if (isLoading() || value === undefined) { + + } @else if (value || value === 0 || value === null) {
} - @if (value === undefined) { - - } - @if (size === 'large') {
diff --git a/libs/ui/src/lib/value/value.component.stories.ts b/libs/ui/src/lib/value/value.component.stories.ts index a5971b252..19139e266 100644 --- a/libs/ui/src/lib/value/value.component.stories.ts +++ b/libs/ui/src/lib/value/value.component.stories.ts @@ -30,6 +30,9 @@ export default { enableCopyToClipboardButton: { control: 'boolean' }, + isLoading: { + control: 'boolean' + }, size: { control: 'select', options: ['small', 'medium', 'large'] @@ -41,7 +44,7 @@ type Story = StoryObj; export const Loading: Story = { args: { - value: undefined + isLoading: true } }; diff --git a/libs/ui/src/lib/value/value.component.ts b/libs/ui/src/lib/value/value.component.ts index 494f7a347..cc08e5a24 100644 --- a/libs/ui/src/lib/value/value.component.ts +++ b/libs/ui/src/lib/value/value.component.ts @@ -62,6 +62,8 @@ export class GfValueComponent implements AfterViewInit, OnChanges, OnDestroy { public readonly copiedTitle = $localize`The value has been copied to the clipboard`; public readonly copyToClipboardTitle = $localize`Copy to clipboard`; + public readonly isLoading = input(false); + public readonly precision = input(); public constructor( private changeDetectorRef: ChangeDetectorRef, @@ -74,8 +76,6 @@ export class GfValueComponent implements AfterViewInit, OnChanges, OnDestroy { }); } - public readonly precision = input(); - private copyToClipboardTimeout: ReturnType; private readonly formatOptions = computed(() => { From 154da3782b1e561770309792e49af7b22b87fcfe Mon Sep 17 00:00:00 2001 From: Sebastian Legarraga <64795732+slegarraga@users.noreply.github.com> Date: Thu, 6 Aug 2026 01:48:16 -0400 Subject: [PATCH 78/86] Task/improve language localization for ES (20260806) (#7549) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.es.xlf | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1171d2fb..b926d2c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Guarded the system tags against deletion and renaming in the tag management of the admin control panel +- Improved the language localization for Spanish (`es`) ### Fixed diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index ab4e4eb3e..866dac527 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -356,7 +356,7 @@ Unknown - Unknown + Desconocido libs/ui/src/lib/i18n.ts 88 @@ -440,7 +440,7 @@ Splits - Splits + Desdoblamientos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 512 @@ -840,7 +840,7 @@ Split Ratio - Split Ratio + Relación de desdoblamiento apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 526 @@ -1776,7 +1776,7 @@ Invalid API key - Invalid API key + Clave de API no válida apps/client/src/app/components/admin-settings/admin-settings.component.html 112 @@ -3056,7 +3056,7 @@ Export - Export + Exportar libs/ui/src/lib/activities-table/activities-table.component.html 68 @@ -4168,7 +4168,7 @@ Cache has been flushed. - Cache has been flushed. + Caché vaciada. apps/client/src/app/components/admin-overview/admin-overview.component.ts 281 @@ -4324,7 +4324,7 @@ Shares After - Shares After + Acciones después apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 584 @@ -5292,7 +5292,7 @@ Do you really want to delete these activities? - Do you really want to delete these activities? + ¿De verdad quieres eliminar estas actividades? libs/ui/src/lib/activities-table/activities-table.component.ts 334 @@ -5758,7 +5758,7 @@ Data gathering has been started. - Data gathering has been started. + La recopilación de datos ha comenzado. apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 413 @@ -7367,7 +7367,7 @@ Shares Before - Shares Before + Acciones antes apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 597 @@ -8170,7 +8170,7 @@ {VAR_PLURAL, plural, =1 {Activity} other {Activities}} - {VAR_PLURAL, plural, =1 {Activity} other {Activities}} + {VAR_PLURAL, plural, =1 {Actividad} other {Actividades}} libs/ui/src/lib/activities-table/activities-table.component.html 69 From 911e12358937f585602b094ab7ab36c38fcdac8b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 6 Aug 2026 07:50:37 +0200 Subject: [PATCH 79/86] Release 3.43.0 (#7552) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b926d2c52..be20727bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 3.43.0 - 2026-08-06 ### Added diff --git a/package-lock.json b/package-lock.json index 06b0efda2..ce97c403b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.42.0", + "version": "3.43.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.42.0", + "version": "3.43.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 4bbda525e..b13aeab4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.42.0", + "version": "3.43.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From c90bb1dfe5b94bb5482b8278e2908c047cea9237 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 6 Aug 2026 20:10:46 +0200 Subject: [PATCH 80/86] Task/refactor abstract Material form field component to directive (#7555) * Migrate to directive * Update changelog --- CHANGELOG.md | 6 ++++++ libs/ui/src/lib/shared/abstract-mat-form-field.ts | 7 ++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be20727bd..736c708e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Migrated the abstract _Material_ form field from a component to a directive + ## 3.43.0 - 2026-08-06 ### Added diff --git a/libs/ui/src/lib/shared/abstract-mat-form-field.ts b/libs/ui/src/lib/shared/abstract-mat-form-field.ts index 0d547af4e..a6ef16175 100644 --- a/libs/ui/src/lib/shared/abstract-mat-form-field.ts +++ b/libs/ui/src/lib/shared/abstract-mat-form-field.ts @@ -1,7 +1,7 @@ import { FocusMonitor } from '@angular/cdk/a11y'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { - Component, + Directive, DoCheck, ElementRef, HostBinding, @@ -13,10 +13,7 @@ import { ControlValueAccessor, NgControl, Validators } from '@angular/forms'; import { MatFormFieldControl } from '@angular/material/form-field'; import { Subject } from 'rxjs'; -@Component({ - template: '', - standalone: false -}) +@Directive() export abstract class AbstractMatFormField implements ControlValueAccessor, DoCheck, MatFormFieldControl, OnDestroy { From 901b52393f8150e91818f1738bfd57210977e963 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Aug 2026 07:48:51 +0200 Subject: [PATCH 81/86] Feature/add country flag to currency selector (#7561) * Add country flag * Update changelog --- CHANGELOG.md | 5 + libs/common/src/lib/helper.spec.ts | 25 +++++ libs/common/src/lib/helper.ts | 11 +++ .../currency-selector.component.html | 10 +- .../currency-selector.component.scss | 3 - .../currency-selector.component.stories.ts | 99 +++++++++++++++++++ .../currency-selector.component.ts | 30 +++++- 7 files changed, 176 insertions(+), 7 deletions(-) delete mode 100644 libs/ui/src/lib/currency-selector/currency-selector.component.scss create mode 100644 libs/ui/src/lib/currency-selector/currency-selector.component.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 736c708e2..32b949274 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added the country flag to the currency selector +- Added a _Storybook_ story for the currency selector component + ### Changed - Migrated the abstract _Material_ form field from a component to a directive diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index 669c42e32..6cc090170 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -4,6 +4,7 @@ import { } from '@ghostfolio/common/config'; import { extractNumberFromString, + getCountryCodeFromCurrency, getNumberFormatGroup, getStringOrNull, getStringOrUndefined, @@ -77,6 +78,30 @@ describe('Helper', () => { }); }); + describe('Get country code from currency', () => { + it('ISO 4217 currency code', () => { + expect(getCountryCodeFromCurrency('CHF')).toEqual('CH'); + expect(getCountryCodeFromCurrency('USD')).toEqual('US'); + }); + + it('Currency of the European Union', () => { + expect(getCountryCodeFromCurrency('EUR')).toEqual('EU'); + }); + + it('Derived currency', () => { + expect(getCountryCodeFromCurrency('GBp')).toEqual('GB'); + }); + + it('Supranational currency', () => { + expect(getCountryCodeFromCurrency('XAU')).toEqual(''); + expect(getCountryCodeFromCurrency('XOF')).toEqual(''); + }); + + it('Empty currency', () => { + expect(getCountryCodeFromCurrency('')).toEqual(''); + }); + }); + describe('Get number format group', () => { let languageGetter: jest.SpyInstance; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 0778f84f1..44fd89aa2 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -279,6 +279,17 @@ export function getCurrencyFromSymbol(aSymbol = '') { return aSymbol.replace(DEFAULT_CURRENCY, ''); } +export function getCountryCodeFromCurrency(aCurrency = '') { + // An ISO 4217 currency code is composed of the ISO 3166-1 alpha-2 country + // code and the initial of the currency itself, except for the supranational + // currencies, which are prefixed with X (like XAU or XOF) + if (aCurrency.startsWith('X')) { + return ''; + } + + return aCurrency.slice(0, 2).toUpperCase(); +} + export function getCountryName({ code }: { code: string }): string { try { return ( diff --git a/libs/ui/src/lib/currency-selector/currency-selector.component.html b/libs/ui/src/lib/currency-selector/currency-selector.component.html index e07101f9a..594515e24 100644 --- a/libs/ui/src/lib/currency-selector/currency-selector.component.html +++ b/libs/ui/src/lib/currency-selector/currency-selector.component.html @@ -1,9 +1,14 @@ +@if (emojiFlagOfSelectedCurrency) { + {{ emojiFlagOfSelectedCurrency }} +} + @for (currency of filteredCurrencies; track currency) { - {{ currency }} + + {{ getEmojiFlagFromCurrency(currency) }} + {{ currency }} + } diff --git a/libs/ui/src/lib/currency-selector/currency-selector.component.scss b/libs/ui/src/lib/currency-selector/currency-selector.component.scss deleted file mode 100644 index 5d4e87f30..000000000 --- a/libs/ui/src/lib/currency-selector/currency-selector.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: block; -} diff --git a/libs/ui/src/lib/currency-selector/currency-selector.component.stories.ts b/libs/ui/src/lib/currency-selector/currency-selector.component.stories.ts new file mode 100644 index 000000000..beb63e369 --- /dev/null +++ b/libs/ui/src/lib/currency-selector/currency-selector.component.stories.ts @@ -0,0 +1,99 @@ +import { ANIMATION_MODULE_TYPE } from '@angular/core'; +import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import '@angular/localize/init'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; + +import { GfCurrencySelectorComponent } from './currency-selector.component'; + +const CURRENCIES = [ + 'AUD', + 'CHF', + 'EUR', + 'GBP', + 'GBp', + 'JPY', + 'USD', + 'XAU', + 'ZAR' +]; + +const meta: Meta = { + title: 'Currency Selector', + component: GfCurrencySelectorComponent, + decorators: [ + moduleMetadata({ + imports: [ + GfCurrencySelectorComponent, + MatFormFieldModule, + ReactiveFormsModule + ], + providers: [ + { + provide: ANIMATION_MODULE_TYPE, + useValue: 'NoopAnimations' + } + ] + }) + ], + render: ({ currencies, value }) => { + return { + props: { + currencies, + formGroup: new FormGroup({ + currency: new FormControl(value) + }) + }, + template: ` +
+ + Currency + + + + ` + }; + } +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + currencies: CURRENCIES, + value: 'CHF' + } +}; + +export const CurrencyOfEuropeanUnion: Story = { + args: { + currencies: CURRENCIES, + value: 'EUR' + } +}; + +export const DerivedCurrency: Story = { + args: { + currencies: CURRENCIES, + value: 'GBp' + } +}; + +export const SupranationalCurrency: Story = { + args: { + currencies: CURRENCIES, + value: 'XAU' + } +}; + +export const WithoutValue: Story = { + args: { + currencies: CURRENCIES, + value: null + } +}; diff --git a/libs/ui/src/lib/currency-selector/currency-selector.component.ts b/libs/ui/src/lib/currency-selector/currency-selector.component.ts index 724e86712..2eda80aba 100644 --- a/libs/ui/src/lib/currency-selector/currency-selector.component.ts +++ b/libs/ui/src/lib/currency-selector/currency-selector.component.ts @@ -1,3 +1,8 @@ +import { + getCountryCodeFromCurrency, + getEmojiFlag +} from '@ghostfolio/common/helper'; + import { FocusMonitor } from '@angular/cdk/a11y'; import { CUSTOM_ELEMENTS_SCHEMA, @@ -24,9 +29,11 @@ import { import { MatAutocomplete, MatAutocompleteModule, + MatAutocompleteOrigin, MatOption } from '@angular/material/autocomplete'; import { + MAT_FORM_FIELD, MatFormFieldControl, MatFormFieldModule } from '@angular/material/form-field'; @@ -39,7 +46,8 @@ import { AbstractMatFormField } from '../shared/abstract-mat-form-field'; changeDetection: ChangeDetectionStrategy.OnPush, host: { '[attr.aria-describedBy]': 'describedBy', - '[id]': 'id' + '[id]': 'id', + class: 'align-items-center d-flex' }, imports: [ FormsModule, @@ -56,7 +64,6 @@ import { AbstractMatFormField } from '../shared/abstract-mat-form-field'; ], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-currency-selector', - styleUrls: ['./currency-selector.component.scss'], templateUrl: 'currency-selector.component.html' }) export class GfCurrencySelectorComponent @@ -72,6 +79,7 @@ export class GfCurrencySelectorComponent public readonly formControlName = input.required(); private readonly destroyRef = inject(DestroyRef); + private readonly formField = inject(MAT_FORM_FIELD); private readonly input = viewChild.required(MatInput); public constructor( @@ -86,8 +94,20 @@ export class GfCurrencySelectorComponent this.controlType = 'currency-selector'; } + public get autocompleteOrigin(): MatAutocompleteOrigin { + return { elementRef: this.formField.getConnectedOverlayOrigin() }; + } + + public get emojiFlagOfSelectedCurrency() { + const selectedCurrency = this.currencies().find((currency) => { + return currency === this.control.value; + }); + + return this.getEmojiFlagFromCurrency(selectedCurrency); + } + public override get empty() { - return this.input().empty; + return !this.control.value; } public override set value(value: string | null) { @@ -99,6 +119,10 @@ export class GfCurrencySelectorComponent this.input().focus(); } + public getEmojiFlagFromCurrency(aCurrency = '') { + return getEmojiFlag(getCountryCodeFromCurrency(aCurrency)); + } + public ngOnInit() { if (this.disabled) { this.control.disable(); From 9b24193042d05de4002636d089e2609442a1af4e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Aug 2026 08:08:00 +0200 Subject: [PATCH 82/86] Feature/add live preview of date and number format to user settings (#7558) * Add live preview of date and number format * Update changelog --- CHANGELOG.md | 1 + .../user-account-settings.component.ts | 9 +++++++ .../user-account-settings.html | 24 +++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32b949274..a610f56ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added a live preview of the date and number format to the user settings - Added the country flag to the currency selector - Added a _Storybook_ story for the currency selector component diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index b48adf59d..18ce8e07c 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -22,6 +22,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + computed, CUSTOM_ELEMENTS_SCHEMA, DestroyRef, inject, @@ -50,6 +51,7 @@ import { format, parseISO } from 'date-fns'; import { addIcons } from 'ionicons'; import { eyeOffOutline, eyeOutline } from 'ionicons/icons'; import ms from 'ms'; +import { DeviceDetectorService } from 'ngx-device-detector'; import { EMPTY, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; @@ -108,10 +110,17 @@ export class GfUserAccountSettingsComponent implements OnInit { 'uk', 'zh' ]; + protected readonly previewDate = new Date().toISOString(); + protected readonly previewValue = 9999.99; protected user: User; + protected readonly deviceType = computed( + () => this.deviceDetectorService.deviceInfo().deviceType + ); + private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly dataService = inject(DataService); + private readonly deviceDetectorService = inject(DeviceDetectorService); private readonly destroyRef = inject(DestroyRef); private readonly notificationService = inject(NotificationService); private readonly settingsStorageService = inject(SettingsStorageService); diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.html b/apps/client/src/app/components/user-account-settings/user-account-settings.html index 57d3b54d7..cb39360f7 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.html +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -146,7 +146,7 @@
-
+
Locale
@@ -154,7 +154,10 @@
- + {{ locale }} } + + + · + +
From 0e3e17580ab838df4273be2ccb6be40d7f741333 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Aug 2026 08:17:56 +0200 Subject: [PATCH 83/86] Task/extend entity logo component by hasPlaceholder attribute (#7553) * Extend entity logo component by hasPlaceholder attribute * Update changelog --- CHANGELOG.md | 1 + .../admin-platform.component.html | 13 +++++----- .../admin-settings.component.html | 6 ++++- .../create-or-update-account-dialog.html | 4 ++- .../transfer-balance-dialog.html | 26 +++++++++---------- .../create-or-update-activity-dialog.html | 16 ++++++------ .../accounts-table.component.html | 26 +++++++++---------- .../activities-table.component.html | 13 +++++----- .../entity-logo/entity-logo.component.html | 7 +++-- .../entity-logo/entity-logo.component.scss | 12 ++++++++- .../entity-logo.component.stories.ts | 16 ++++++++++++ .../lib/entity-logo/entity-logo.component.ts | 12 ++++++++- .../entity-logo-image-source.service.mock.ts | 7 +++-- .../portfolio-filter-form.component.html | 13 +++++----- 14 files changed, 107 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a610f56ef..83861a8d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a live preview of the date and number format to the user settings - Added the country flag to the currency selector - Added a _Storybook_ story for the currency selector component +- Extended the entity logo component by a `hasPlaceholder` attribute to reserve the space of a missing logo ### Changed diff --git a/apps/client/src/app/components/admin-platform/admin-platform.component.html b/apps/client/src/app/components/admin-platform/admin-platform.component.html index 19682bdc0..7c699e557 100644 --- a/apps/client/src/app/components/admin-platform/admin-platform.component.html +++ b/apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -22,13 +22,12 @@ Name
diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.html b/apps/client/src/app/components/admin-settings/admin-settings.component.html index 99346f0fb..b3ad389d6 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.html +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -59,7 +59,11 @@ @@ -98,13 +97,12 @@ mat-cell >
- @if (element.platform?.url) { - - } + {{ element.platform?.name }}
diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index bf7fb2caf..7f53da4fa 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -356,13 +356,12 @@
- @if (element.url) { - - } + {{ element.name }}
- +
@if (isGhostfolioDataProvider(element)) { Platform - @if (selectedPlatform?.url) { + @if (selectedPlatform) { @@ -71,6 +72,7 @@ diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html index 50c96be86..2f74bfbe7 100644 --- a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html @@ -13,13 +13,12 @@ @for (account of accounts; track account) {
- @if (account.platform?.url) { - - } + {{ account.name }}
@@ -34,13 +33,12 @@ @for (account of accounts; track account) {
- @if (account.platform?.url) { - - } + {{ account.name }}
diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html index b3c708167..9455a9dd6 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -87,9 +87,10 @@
- @if (selectedAccount?.platform?.url) { + @if (selectedAccount) { @@ -103,13 +104,12 @@ @for (account of data.accounts; track account) {
- @if (account.platform?.url) { - - } + {{ account.name }}
diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.html b/libs/ui/src/lib/accounts-table/accounts-table.component.html index d252b1488..1d1cbb296 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.html +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -50,13 +50,12 @@ Name
- @if (element.platform?.url) { - - } + {{ element.name }} Total
- @if (element.account?.platform?.url) { - - } + {{ element.account?.name }} diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.html b/libs/ui/src/lib/entity-logo/entity-logo.component.html index d8aeba136..0a7ecbcd2 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.html +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.html @@ -1,8 +1,11 @@ -@if (src) { +@if (src && !hasError) { +} @else if (hasPlaceholder) { + } diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.scss b/libs/ui/src/lib/entity-logo/entity-logo.component.scss index 23bc7a487..051199346 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.scss +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.scss @@ -2,7 +2,7 @@ align-items: center; display: flex; - img { + .logo { border-radius: 0.2rem; height: 0.8rem; width: 0.8rem; @@ -11,5 +11,15 @@ height: 1.4rem; width: 1.4rem; } + + &.placeholder { + border: 1px solid rgba(var(--dark-dividers)); + } + } +} + +:host-context(.theme-dark) { + .placeholder { + border-color: rgba(var(--light-dividers)); } } diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts b/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts index 45a996294..786d54cbf 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts @@ -44,3 +44,19 @@ export const LogoByUrl: Story = { url: 'https://ghostfol.io' } }; + +export const Placeholder: Story = { + args: { + hasPlaceholder: true, + size: 'large' + } +}; + +export const PlaceholderOnError: Story = { + args: { + hasPlaceholder: true, + size: 'large', + tooltip: 'Unknown', + url: 'https://unknown.ghostfol.io' + } +}; diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.ts b/libs/ui/src/lib/entity-logo/entity-logo.component.ts index ba7d64ae0..ef8e72105 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.ts +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.ts @@ -18,18 +18,22 @@ import { DataSource } from '@prisma/client'; }) export class GfEntityLogoComponent implements OnChanges { @Input() dataSource: DataSource; + @Input() hasPlaceholder = false; @Input() size: 'large'; @Input() symbol: string; @Input() tooltip: string; @Input() url: string; - public src: string; + public hasError = false; + public src?: string; public constructor( private readonly imageSourceService: EntityLogoImageSourceService ) {} public ngOnChanges() { + this.hasError = false; + if (this.dataSource && this.symbol) { this.src = this.imageSourceService.getLogoUrlByAssetProfileIdentifier({ dataSource: this.dataSource, @@ -37,6 +41,12 @@ export class GfEntityLogoComponent implements OnChanges { }); } else if (this.url) { this.src = this.imageSourceService.getLogoUrlByUrl(this.url); + } else { + this.src = undefined; } } + + public onError() { + this.hasError = true; + } } diff --git a/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts b/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts index 3f4dbbef7..766a4178b 100644 --- a/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts +++ b/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts @@ -2,6 +2,9 @@ import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; import { DataSource } from '@prisma/client'; +// Resolves like a logo of an unknown entity, but fails to load +const UNAVAILABLE_LOGO_URL = 'data:image/png;base64,unavailable'; + export class EntityLogoImageSourceServiceMock { public getLogoUrlByAssetProfileIdentifier({ dataSource, @@ -11,7 +14,7 @@ export class EntityLogoImageSourceServiceMock { return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAJa0lEQVR4nM2bW2wU1xnHf3vx2t61za5nL/bGKwx2jQnwUh5Q3bqyHYhzIVLUFoIaSKtGSrkkNaQJqlQSKaHQFygQJamUSomaRKpSlYekqSF1HGix6EOktIldOQs0OCEs3ssw48Ve8F77MGuwza4ve2Y3/KR92Ln8z/d9OnPmnG/OZ/jss2FKRA3QCiwDPEAtUAEkgWvAGKAAF4HPgWgpjDIXUdsF3AN0Zn/NVmuFoazMgtlswmw2YTAYyGQgnU6TSqVIpdIkEnFisRsZ4AJwGjgFfAiEi2GkQeceUAn8CPgJ0GG315hsNis2m5XycsuihCYn40xMxJiYiKGq0RRaMP4I/AW4rpfBegXAAfQAu+z2JU6HowabzYbBoIc0ZDIwMTGBokRR1bEI8ApwDO2REUI0AGbgKeB5t1uyS1ItZrNJ1KY5SSZTyPJVQiFZBfYDL6GNIwUhEoDvAr+XJMcaSXIsuouLEo/HiUQUZFkZBHYCA4XoGAu4xwS8APzD5/Ou8Xo9JXcewGKx4PV68Pm8a9DGhxezti2KxfYAF/COJDk63W5n0bv7QkkmU4RCEWRZOQU8wiLeGIvpAY3AgNvt7PR6PXeM8wBmswmv14Pb7exEexQaF3rvQgOwCjhbV+dq8XicBZhYGjweJ3V1rhbgLJrN87KQADQBJ71eT73LJYnYVxJcLgmv11MPnASa57t+vgC4gJP19e4GSXLoYV9JkCQH9fXuBuAEmg95mSsAZcBxt9vZ7HTW6mlfXsbHJzh27CU6Ojppbm7h4sWLBWs5nbW43c5m4DiaLzmZay2wX5Ic7aV65s+dO8fu3U8zNDQEgM1mo7q6WkjT43GSSqXaZVnZD/wq1zX5esD3gGfr6ubsPbpx/vx5tm597KbzAK2tK6itFe95WR+eRfPpNnIFwAy86vN5jUZjIfOkxTE5Ocnu3U8zOjo64/hDD21Ej/aNRiM+n9cIvEqOHp+rhR5Jcqyx22uEG18IfX19DA4OzjhWX1/Pww8/rFsbdnsNkuRYA/xi9rnZAagB9pVq0AN4//3eGf+rq6s5cuSwLt1/Ok6nA+A5NB9vMjsAO10uyW6x5B00dSWRSPDpp/+5+b+lpYW3336LtrY23duyWCy4XJIdbeF0k+nPRCWwR5Lsujeej3Q6zbJly1m6dCnd3d1s27YVs7l4SSpJshMOy3uAo8ANmLkY2mK31/zJ5/Pq1qAsy/T1fcjg4CCKomK1VrJy5Uo6Ojpoalp+2/VDQ0P09X2I33+O8fFrlJdX4PXW09bWRldXJ+Xl5cI2ffVVgLGx6BbgHZgZgL81NjY8UF1dJdxIMpnktdf+wOuvv0EoFLrtfEVFBV1dXWzc+AB33dXA4OAg7733Vz7++GMymUxOzdbWVvbufYb169cL2Xbt2jgjI1/3Ag/CrQC4gMDq1SvMBsE81uTkJDt3PklfX5+QTj4OHjzA1q2PFnx/JpNhaMifBLxAeGoQvMdurxF2PpVK0dOzp2jOA+zb9xx+v7/g+w0GA3Z7jRktY33zLdBls1mFjXvrrbfp7e2d/8ICMRgMHDjwG5qamoR0sr52wa23QGdVlVgAotEoL7/8ipDGfDz//HM8+uiPhXWyAegArQdYgeUWi1he78SJkzkHPL3o7r6Xxx//mS5a2RxmE1BpBJorKsqFJ939/f2iEnkxmUw89dSTumpmff6WEWjVI6s7MvKlsEY+li9fzqpVC8pwLZiszyuMQH1ZmfjsKxodE9bIR3NzEyaTvknY7Iyz3gg49BCfnIwLa+SjslL8DTWbrM8OI1Au+v4HdFm750NRruquaTQaACqMQCrP7HNR2Gw2cZE8DA9/TiwW01Uz63PSCFxLp9PCgnb7EmGNfIyOjnL69GldNbM+jxuBaDqdEhZctmyZsMZcHDlyTNdekPU5agTkZFI8AOvWrRPWmAu/309Pz24SiYQuelmfw0bgcz1G8La271BWVtxM0gcf/J0nntjO5cuXhbWyPp8zAhdu3JgUHgQaGxtZu/bbwobNR39/P5s2PSKsk/X5vBGIAV/E4+K9YMuWLcIaCyGZLHhDCKBtrgC+AK5PvbxPjY+LDzD33deNz+cT1pmPzZs3Cd2f9fUU3MoHfDQxIR4Aq9XKrl07hHXmora2lm3btgppZH2dEYB+VY0m8+XjFsPmzZtZvXq1sE4+duzYjsfjKfj+TCaDqkaTQD/cCkAY6NPjMTCbzezf/0JR0tt3372Sxx7bJqSR9bEPCMHMDyNvqqo+K7q1a9eyd++zumhNUVVl4/DhQ1RWVgrpZH18c+r/9AC8q6rRsF4Tje3bfy78rE5hNps5evSocE4gkUigqtEQ8O5N7WnnrwO/k2X1t3p9Fn/xxReIxa5z/PjxGcdtNhvr199De3s7DQ0NxONx/H4/J06c4JNP/j3j2qoqGwcPHuTeezcI2yPLKsARpm21nb1Nrgb4csWKJl2/D/b29nLmzACJRIKWlhY2bFifc+2QyWQYGBjg7Nl/oSgqdXUeNm58kObmebf6zEs8nsDv/58KLGXaTvRc+wR/KUmOQ15v4SPtnUggEESWlWeAw9OP58piHJNlZUhVS7JdvySoanRqS+2x2edyBSAJ7Lh0KZDWI0/wTZNOp7l0KZBG+yx+2xw6Xx5rADg0OlqUGoWSEgyGAQ6RZzP1XIm8fbKsnAkGI8WwqyQEgxEiEWUAbWdITuYKQAL4YSgUuRCJ6J+ULDaRyFVCocgF4AdA3qXufKncMHD/lSuhr2VZuDijZMiywpUrocvA/cyzc3whuewLwH2BQPBKOCzrYV9RCYdlAoHgFaAbzfY5WWgy/79A2+ho+NydPCYEgxFGR8MXgDY0m+dlMV8zRoD2UChyKhAIokciVS+SyRSBQJBQKHIKrZRnZKH3LvZzTgjYIMvK/uHh8+k7YbKkqlGGh8+ns/uBN5Bd5i4UkaKpduBVSXKsdjprKdXewini8QSRyFVkWRlCm+ScKURHj7K5HuDXLpfkkCQHenxpnotEIoksK4TDsgIcQJvefiNlc9OpAZ4EehyOJW6HYwlWq1XXwslYLIaijKEoYyE0p19Gh/riYpTObgJ+Cnx/qnS2qsrKYrfgxONxxsdnlM7+E6109s/cgaWzufCg7cTqAjqMRmNzRUU5ZWVllJWZMJnyFU8nuHFjknQ6PVU8/VH2FyyGkcUMwGxqgJVoJW11gARYuL18fgQYpkTl8/8HqhBYlUKrXOwAAAAASUVORK5CYII='; } - return ''; + return UNAVAILABLE_LOGO_URL; } public getLogoUrlByUrl(url: string) { @@ -19,6 +22,6 @@ export class EntityLogoImageSourceServiceMock { return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAP1BMVEU2z8v////x/Pspzcn0/Px73drR8/KC3tz6/v6e5eOl5+WM4d7n+PhI08/i9/eu6edV1dJk2NVx2teV4+G87evvttLSAAABDElEQVRYhe2V3Y6EIAyFrQXlTwHd93/WpeBsdiKbtF7tJJwbCKFfDlKO0zQ0NPQJwqrn1ZO2zlk9PWPgusClRcsJmHb4pWUTItDDu4zMBJ5w0yog4HGvB0gCgOoBZrYFdL16AMsmmD5AcQ3ofj3AwbOAX38BIhMw02ZjtQ+tLnht66mCAGA2eka1G3eabUZwD/PLbeuHenKMBODVV0Dru/TTQLgKAc1BvQ/9yAEkOnlon66oehEBIHp7dbSyPoIc0NEADMDnAa4wAvVK+CADRGx/VpNSi+iF3jMTUH4rJQ0aISPmVk+JoJiZeJw1QnaqL2OmWKSFkxnrZWsbXK4TzO5tmS+8TYaGhv6xvgEEfAgHGc7HRgAAAABJRU5ErkJggg=='; } - return ''; + return UNAVAILABLE_LOGO_URL; } } diff --git a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html index cda9cab3c..6c8902112 100644 --- a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html +++ b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html @@ -7,13 +7,12 @@ @for (account of accounts(); track account.id) {
- @if (account.platform?.url) { - - } + {{ account.name }}
From 57c21846827688702cd3401c3547ce2800c84bd1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Aug 2026 08:42:30 +0200 Subject: [PATCH 84/86] Task/improve usability of create watchlist item dialog (#7559) * Set initial focus to search field * Update changelog --- CHANGELOG.md | 1 + .../app/components/home-watchlist/home-watchlist.component.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83861a8d0..dc1e4b745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the usability of the create watchlist item dialog by setting the initial focus to the search field - Migrated the abstract _Material_ form field from a component to a directive ## 3.43.0 - 2026-08-06 diff --git a/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts b/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts index 0107f36a2..97fa6f744 100644 --- a/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts +++ b/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts @@ -146,7 +146,6 @@ export class GfHomeWatchlistComponent implements OnInit { GfCreateWatchlistItemDialogComponent, CreateWatchlistItemDialogParams >(GfCreateWatchlistItemDialogComponent, { - autoFocus: false, data: { deviceType: this.deviceType(), locale: this.user?.settings?.locale ?? DEFAULT_LOCALE From ddd20d30998542dcf80ce3dd31b3dd23206e8eb0 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:00:30 +0200 Subject: [PATCH 85/86] Task/remove redundant balance attribute from account (#7546) * Remove redundant balance attribute from account * Update changelog --- CHANGELOG.md | 1 + .../api/src/app/account/account.controller.ts | 92 +++++++++---------- apps/api/src/app/account/account.service.ts | 80 +++++++++------- .../interfaces/cash-details.interface.ts | 4 +- apps/api/src/app/export/export.service.ts | 4 +- apps/api/src/app/import/import.service.ts | 12 ++- .../app/portfolio/portfolio.service.spec.ts | 7 +- .../src/app/portfolio/portfolio.service.ts | 4 +- .../holding-detail-dialog.component.ts | 5 +- .../pages/accounts/accounts-page.component.ts | 9 +- .../interfaces/interfaces.ts | 8 +- libs/common/src/lib/config.ts | 2 - .../common/src/lib/dtos/create-account.dto.ts | 7 +- .../common/src/lib/dtos/update-account.dto.ts | 7 +- .../lib/types/account-with-balance.type.ts | 5 + .../src/lib/types/account-with-value.type.ts | 6 +- libs/common/src/lib/types/index.ts | 2 + .../accounts-table.component.stories.ts | 20 ++-- .../accounts-table.component.ts | 14 +-- .../activities-table.component.stories.ts | 5 - .../migration.sql | 2 + prisma/schema.prisma | 1 - test/import/not-ok/invalid-platform.json | 1 - test/import/ok/500-activities.json | 1 - test/import/ok/derived-currency.json | 1 - test/import/ok/sample.json | 1 - 26 files changed, 171 insertions(+), 130 deletions(-) create mode 100644 libs/common/src/lib/types/account-with-balance.type.ts create mode 100644 prisma/migrations/20260805120000_removed_balance_from_account/migration.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index dc1e4b745..4656bdedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the usability of the create watchlist item dialog by setting the initial focus to the search field - Migrated the abstract _Material_ form field from a component to a directive +- Removed the redundant `balance` attribute of the account in favor of the account balances ## 3.43.0 - 2026-08-06 diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 6466a13b2..f43aeedd5 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -156,32 +156,34 @@ export class AccountController { public async createAccount( @Body() data: CreateAccountDto ): Promise { - const { tags: tagIds, ...accountData } = data; + const { balance, tags: tagIds, ...accountData } = data; if (accountData.platformId) { const platformId = accountData.platformId; delete accountData.platformId; - return this.accountService.createAccount( - { + return this.accountService.createAccount({ + balance, + tagIds, + data: { ...accountData, platform: { connect: { id: platformId } }, user: { connect: { id: this.request.user.id } } }, - this.request.user.id, - tagIds - ); + userId: this.request.user.id + }); } else { delete accountData.platformId; - return this.accountService.createAccount( - { + return this.accountService.createAccount({ + balance, + tagIds, + data: { ...accountData, user: { connect: { id: this.request.user.id } } }, - this.request.user.id, - tagIds - ); + userId: this.request.user.id + }); } } @@ -257,52 +259,50 @@ export class AccountController { ); } - const { tags: tagIds, ...accountData } = data; + const { balance, tags: tagIds, ...accountData } = data; if (accountData.platformId) { const platformId = accountData.platformId; delete accountData.platformId; - return this.accountService.updateAccount( - { - data: { - ...accountData, - platform: { connect: { id: platformId } }, - user: { connect: { id: this.request.user.id } } - }, - where: { - id_userId: { - id, - userId: this.request.user.id - } - } + return this.accountService.updateAccount({ + balance, + tagIds, + data: { + ...accountData, + platform: { connect: { id: platformId } }, + user: { connect: { id: this.request.user.id } } }, - this.request.user.id, - tagIds - ); + userId: this.request.user.id, + where: { + id_userId: { + id, + userId: this.request.user.id + } + } + }); } else { // platformId is null, remove it delete accountData.platformId; - return this.accountService.updateAccount( - { - data: { - ...accountData, - platform: originalAccount.platformId - ? { disconnect: true } - : undefined, - user: { connect: { id: this.request.user.id } } - }, - where: { - id_userId: { - id, - userId: this.request.user.id - } - } + return this.accountService.updateAccount({ + balance, + tagIds, + data: { + ...accountData, + platform: originalAccount.platformId + ? { disconnect: true } + : undefined, + user: { connect: { id: this.request.user.id } } }, - this.request.user.id, - tagIds - ); + userId: this.request.user.id, + where: { + id_userId: { + id, + userId: this.request.user.id + } + } + }); } } } diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 7f0451101..3d0bb91bd 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -10,6 +10,7 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { Filter } from '@ghostfolio/common/interfaces'; +import { AccountWithBalance } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; @@ -24,7 +25,7 @@ import { } from '@prisma/client'; import { Big } from 'big.js'; import { endOfToday, format } from 'date-fns'; -import { groupBy } from 'lodash'; +import { groupBy, isNil } from 'lodash'; import { CashDetails } from './interfaces/cash-details.interface'; @@ -40,7 +41,7 @@ export class AccountService { public async account({ id_userId - }: Prisma.AccountWhereUniqueInput): Promise { + }: Prisma.AccountWhereUniqueInput): Promise { const account = await this.prismaService.account.findUnique({ include: { balances: { @@ -87,7 +88,7 @@ export class AccountService { where?: Prisma.AccountWhereInput; orderBy?: Prisma.AccountOrderByWithRelationInput; }): Promise< - (Account & { + (AccountWithBalance & { activities?: (Order & { SymbolProfile?: SymbolProfile })[]; balances?: AccountBalance[]; platform?: Platform; @@ -160,12 +161,18 @@ export class AccountService { }); } - public async createAccount( - data: Prisma.AccountCreateInput, - aUserId: string, - tagIds?: string[] - ): Promise { - await this.tagService.validateTagIds({ tagIds, userId: aUserId }); + public async createAccount({ + balance, + data, + tagIds, + userId + }: { + balance?: number; + data: Prisma.AccountCreateInput; + tagIds?: string[]; + userId: string; + }): Promise { + await this.tagService.validateTagIds({ tagIds, userId }); const account = await this.prismaService.account.create({ data: { @@ -182,12 +189,14 @@ export class AccountService { } }); - await this.accountBalanceService.createOrUpdateAccountBalance({ - accountId: account.id, - balance: data.balance, - date: format(new Date(), DATE_FORMAT), - userId: aUserId - }); + if (!isNil(balance)) { + await this.accountBalanceService.createOrUpdateAccountBalance({ + balance, + userId, + accountId: account.id, + date: format(new Date(), DATE_FORMAT) + }); + } this.eventEmitter.emit( PortfolioChangedEvent.getName(), @@ -216,7 +225,7 @@ export class AccountService { return account; } - public async getAccounts(aUserId: string): Promise { + public async getAccounts(aUserId: string): Promise { const accounts = await this.accounts({ include: { activities: true, @@ -295,17 +304,20 @@ export class AccountService { }; } - public async updateAccount( - params: { - data: Prisma.AccountUpdateInput; - where: Prisma.AccountWhereUniqueInput; - }, - aUserId: string, - tagIds?: string[] - ): Promise { - const { data, where } = params; - - await this.tagService.validateTagIds({ tagIds, userId: aUserId }); + public async updateAccount({ + balance, + data, + tagIds, + userId, + where + }: { + balance?: number; + data: Prisma.AccountUpdateInput; + tagIds?: string[]; + userId: string; + where: Prisma.AccountWhereUniqueInput; + }): Promise { + await this.tagService.validateTagIds({ tagIds, userId }); const account = await this.prismaService.account.update({ data: { @@ -324,12 +336,14 @@ export class AccountService { where }); - await this.accountBalanceService.createOrUpdateAccountBalance({ - accountId: account.id, - balance: data.balance as number, - date: format(new Date(), DATE_FORMAT), - userId: aUserId - }); + if (!isNil(balance)) { + await this.accountBalanceService.createOrUpdateAccountBalance({ + balance, + userId, + accountId: account.id, + date: format(new Date(), DATE_FORMAT) + }); + } this.eventEmitter.emit( PortfolioChangedEvent.getName(), diff --git a/apps/api/src/app/account/interfaces/cash-details.interface.ts b/apps/api/src/app/account/interfaces/cash-details.interface.ts index 715343766..b396328a5 100644 --- a/apps/api/src/app/account/interfaces/cash-details.interface.ts +++ b/apps/api/src/app/account/interfaces/cash-details.interface.ts @@ -1,6 +1,6 @@ -import { Account } from '@prisma/client'; +import { AccountWithBalance } from '@ghostfolio/common/types'; export interface CashDetails { - accounts: Account[]; + accounts: AccountWithBalance[]; balanceInBaseCurrency: number; } diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 02ccb46b3..35db20993 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -102,7 +102,6 @@ export class ExportService { }) .map( ({ - balance, balances, comment, currency, @@ -111,13 +110,12 @@ export class ExportService { platform, platformId, tags - }) => { + }): ExportResponse['accounts'][number] => { if (platformId) { platformsMap[platformId] = platform; } return { - balance, balances: balances.map(({ date, value }) => { return { date: date.toISOString(), value }; }), diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 96612522e..9d1e899c3 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -355,6 +355,7 @@ export class ImportService { // If there is no account or if the account belongs to a different user then create a new account if (!accountWithSameId || accountWithSameId.userId !== user.id) { const account = omit(accountWithBalances, [ + 'balance', 'balances', 'isExcluded', 'tags' @@ -408,11 +409,12 @@ export class ImportService { }; } - const newAccount = await this.accountService.createAccount( - accountObject, - user.id, - tagIds - ); + const newAccount = await this.accountService.createAccount({ + tagIds, + balance: accountWithBalances.balance, + data: accountObject, + userId: user.id + }); // Store the new to old account ID mappings for updating activities if (accountWithSameId && oldAccountId) { diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index 97635553f..eed3a27cb 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -16,8 +16,9 @@ import { AssetProfileIdentifier, PortfolioSummary } from '@ghostfolio/common/interfaces'; +import { AccountWithBalance } from '@ghostfolio/common/types'; -import { Account, DataSource } from '@prisma/client'; +import { DataSource } from '@prisma/client'; import { Big } from 'big.js'; import { randomUUID } from 'node:crypto'; @@ -219,7 +220,7 @@ describe('PortfolioService', () => { it('should return cash holdings when the calculator emits cash positions with the exchange-rate data source', async () => { const accountId = randomUUID(); - const cashAccount: Account = { + const cashAccount: AccountWithBalance = { balance: 2000, comment: null, createdAt: parseDate('2024-01-01'), @@ -444,7 +445,7 @@ describe('PortfolioService', () => { beforeEach(() => { jest .spyOn(accountService, 'getAccounts') - .mockResolvedValue([account] as unknown as Account[]); + .mockResolvedValue([account] as unknown as AccountWithBalance[]); jest .spyOn(exchangeRateDataService, 'toCurrency') diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 70106bdc1..ef79fd717 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -64,6 +64,7 @@ import { } from '@ghostfolio/common/interfaces'; import { TimelinePosition } from '@ghostfolio/common/models'; import { + AccountWithBalance, AccountWithValue, DateRange, GroupBy, @@ -75,7 +76,6 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Inject, Injectable, Logger } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { - Account, Type as ActivityType, AssetClass, AssetSubClass, @@ -2142,7 +2142,7 @@ export class PortfolioService { const accounts: PortfolioDetails['accounts'] = {}; const platforms: PortfolioDetails['platforms'] = {}; - let currentAccounts: (Account & { + let currentAccounts: (AccountWithBalance & { Order?: Order[]; platform?: Platform; tags?: Tag[]; diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index d58349fa0..57b8196d6 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -22,6 +22,7 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; +import { AccountWithValue } from '@ghostfolio/common/types'; import { GfAccountsTableComponent } from '@ghostfolio/ui/accounts-table'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfDataProviderCreditsComponent } from '@ghostfolio/ui/data-provider-credits'; @@ -65,7 +66,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { NavigationStart, Router, RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; -import { Account, MarketData, Tag } from '@prisma/client'; +import { MarketData, Tag } from '@prisma/client'; import { isUUID } from 'class-validator'; import { format, isSameMonth, isToday, parseISO } from 'date-fns'; import { addIcons } from 'ionicons'; @@ -117,7 +118,7 @@ import { templateUrl: 'holding-detail-dialog.html' }) export class GfHoldingDetailDialogComponent implements OnInit { - protected accounts: Account[]; + protected accounts: AccountWithValue[]; protected activitiesCount: number; protected assetClass: string; protected assetProfile: Pick< diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index 291a7f3f9..e45c1d003 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -12,6 +12,7 @@ import { } from '@ghostfolio/common/dtos'; import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { AccountWithValue } from '@ghostfolio/common/types'; import { GfAccountsTableComponent } from '@ghostfolio/ui/accounts-table'; import { GfFabComponent } from '@ghostfolio/ui/fab'; import { NotificationService } from '@ghostfolio/ui/notifications'; @@ -29,7 +30,7 @@ import { import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; -import { Account as AccountModel, Tag } from '@prisma/client'; +import { Tag } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; import { EMPTY } from 'rxjs'; import { catchError } from 'rxjs/operators'; @@ -48,7 +49,7 @@ import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-ba templateUrl: './accounts-page.html' }) export class GfAccountsPageComponent implements OnInit { - protected accounts: AccountModel[]; + protected accounts: AccountWithValue[]; protected activitiesCount = 0; protected hasImpersonationId: boolean; protected hasPermissionToCreateAccount: boolean; @@ -155,7 +156,7 @@ export class GfAccountsPageComponent implements OnInit { }); } - protected onUpdateAccount(aAccount: AccountModel) { + protected onUpdateAccount(aAccount: AccountWithValue) { this.router.navigate([], { queryParams: { accountId: aAccount.id, editDialog: true } }); @@ -194,7 +195,7 @@ export class GfAccountsPageComponent implements OnInit { name, platformId, tags - }: AccountModel & { tags?: Tag[] }) { + }: AccountWithValue & { tags?: Tag[] }) { const dialogRef = this.dialog.open< GfCreateOrUpdateAccountDialogComponent, CreateOrUpdateAccountDialogParams diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts index c51503277..43015de00 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/interfaces/interfaces.ts @@ -1,9 +1,13 @@ import { User } from '@ghostfolio/common/interfaces'; +import { AccountWithBalance } from '@ghostfolio/common/types'; -import { Account, Tag } from '@prisma/client'; +import { Tag } from '@prisma/client'; export interface CreateOrUpdateAccountDialogParams { - account: Omit & { + account: Omit< + AccountWithBalance, + 'createdAt' | 'id' | 'updatedAt' | 'userId' + > & { id: string | null; tags?: Tag[]; }; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 08a6701dc..23c8aab69 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -115,7 +115,6 @@ export const DEFAULT_REDACTED_PATHS = [ 'accounts[*].interestInBaseCurrency', 'accounts[*].value', 'accounts[*].valueInBaseCurrency', - 'activities[*].account.balance', 'activities[*].account.comment', 'activities[*].assetProfile.symbolMapping', 'activities[*].assetProfile.watchedByCount', @@ -128,7 +127,6 @@ export const DEFAULT_REDACTED_PATHS = [ 'activities[*].valueInBaseCurrency', 'balance', 'balanceInBaseCurrency', - 'balances[*].account.balance', 'balances[*].account.comment', 'balances[*].value', 'balances[*].valueInBaseCurrency', diff --git a/libs/common/src/lib/dtos/create-account.dto.ts b/libs/common/src/lib/dtos/create-account.dto.ts index cae8293ee..ccadff5f9 100644 --- a/libs/common/src/lib/dtos/create-account.dto.ts +++ b/libs/common/src/lib/dtos/create-account.dto.ts @@ -12,8 +12,13 @@ import { import { isString } from 'lodash'; export class CreateAccountDto { + /** + * The initial balance, stored as the account balance of today. + * Optional because callers may instead supply the full history via `balances`. + */ @IsNumber() - balance: number; + @IsOptional() + balance?: number; @IsOptional() @IsString() diff --git a/libs/common/src/lib/dtos/update-account.dto.ts b/libs/common/src/lib/dtos/update-account.dto.ts index d8bfc7b8d..4e1570aad 100644 --- a/libs/common/src/lib/dtos/update-account.dto.ts +++ b/libs/common/src/lib/dtos/update-account.dto.ts @@ -12,8 +12,13 @@ import { import { isString } from 'lodash'; export class UpdateAccountDto { + /** + * The balance, stored as the account balance of today. + * Optional because the account balances are the source of truth. + */ @IsNumber() - balance: number; + @IsOptional() + balance?: number; @IsOptional() @IsString() diff --git a/libs/common/src/lib/types/account-with-balance.type.ts b/libs/common/src/lib/types/account-with-balance.type.ts new file mode 100644 index 000000000..72732f3a6 --- /dev/null +++ b/libs/common/src/lib/types/account-with-balance.type.ts @@ -0,0 +1,5 @@ +import { Account as AccountModel } from '@prisma/client'; + +export type AccountWithBalance = AccountModel & { + balance: number; +}; diff --git a/libs/common/src/lib/types/account-with-value.type.ts b/libs/common/src/lib/types/account-with-value.type.ts index a13530632..27b7541dc 100644 --- a/libs/common/src/lib/types/account-with-value.type.ts +++ b/libs/common/src/lib/types/account-with-value.type.ts @@ -1,6 +1,8 @@ -import { Account as AccountModel, Platform, Tag } from '@prisma/client'; +import { Platform, Tag } from '@prisma/client'; -export type AccountWithValue = AccountModel & { +import { AccountWithBalance } from './account-with-balance.type'; + +export type AccountWithValue = AccountWithBalance & { activitiesCount: number; allocationInPercentage: number; balanceInBaseCurrency: number; diff --git a/libs/common/src/lib/types/index.ts b/libs/common/src/lib/types/index.ts index aa6893bc6..f61bfdca7 100644 --- a/libs/common/src/lib/types/index.ts +++ b/libs/common/src/lib/types/index.ts @@ -1,5 +1,6 @@ import type { AccessType } from './access-type.type'; import type { AccessWithGranteeUser } from './access-with-grantee-user.type'; +import type { AccountWithBalance } from './account-with-balance.type'; import type { AccountWithPlatform } from './account-with-platform.type'; import type { AccountWithValue } from './account-with-value.type'; import type { AiPromptMode } from './ai-prompt-mode.type'; @@ -28,6 +29,7 @@ import type { ViewMode } from './view-mode.type'; export type { AccessType, AccessWithGranteeUser, + AccountWithBalance, AccountWithPlatform, AccountWithValue, AiPromptMode, diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts index a38ca826c..68da20ec6 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts @@ -1,3 +1,5 @@ +import { AccountWithValue } from '@ghostfolio/common/types'; + import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { MatMenuModule } from '@angular/material/menu'; @@ -14,16 +16,18 @@ import { NotificationService } from '../notifications'; import { GfValueComponent } from '../value'; import { GfAccountsTableComponent } from './accounts-table.component'; -const accounts = [ +const accounts: AccountWithValue[] = [ { activitiesCount: 0, - allocationInPercentage: null, + allocationInPercentage: 0.002574748676949956, balance: 278, balanceInBaseCurrency: 278, comment: null, createdAt: new Date('2025-06-01T06:52:49.063Z'), currency: 'USD', + dividendInBaseCurrency: 0, id: '460d7401-ca43-4ed4-b08e-349f1822e9db', + interestInBaseCurrency: 0, name: 'Coinbase Account', platform: { id: '8dc24b88-bb92-4152-af25-fe6a31643e26', @@ -38,13 +42,15 @@ const accounts = [ }, { activitiesCount: 0, - allocationInPercentage: null, + allocationInPercentage: 0.11114023065971035, balance: 12000, balanceInBaseCurrency: 12000, comment: null, createdAt: new Date('2025-06-01T06:48:53.055Z'), currency: 'USD', + dividendInBaseCurrency: 0, id: '6d773e31-0583-4c85-a247-e69870b4f1ee', + interestInBaseCurrency: 0, name: 'Private Banking Account', platform: { id: '43e8fcd1-5b79-4100-b678-d2229bd1660d', @@ -59,13 +65,15 @@ const accounts = [ }, { activitiesCount: 12, - allocationInPercentage: null, + allocationInPercentage: 0.8862850206633397, balance: 150.2, balanceInBaseCurrency: 150.2, comment: null, createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', + dividendInBaseCurrency: 0, id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', + interestInBaseCurrency: 0, name: 'Trading Account', platform: { id: '9da3a8a7-4795-43e3-a6db-ccb914189737', @@ -73,10 +81,10 @@ const accounts = [ url: 'https://interactivebrokers.com' }, platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', - valueInBaseCurrency: 95693.70321466809, updatedAt: new Date('2025-06-01T06:53:10.569Z'), userId: '081aa387-487d-4438-83a4-3060eb2a016e', - value: 95693.70321466809 + value: 95693.70321466809, + valueInBaseCurrency: 95693.70321466809 } ]; diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.ts index 3e531e844..ab49c8cb5 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.ts @@ -4,6 +4,7 @@ import { getLowercase, isAccountExcluded } from '@ghostfolio/common/helper'; +import { AccountWithValue } from '@ghostfolio/common/types'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -24,7 +25,6 @@ import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { Router, RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; -import { Account } from '@prisma/client'; import { addIcons } from 'ionicons'; import { arrowRedoOutline, @@ -55,7 +55,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; templateUrl: './accounts-table.component.html' }) export class GfAccountsTableComponent { - public readonly accounts = input.required(); + public readonly accounts = input.required(); public readonly activitiesCount = input(); public readonly baseCurrency = input(); public readonly hasPermissionToOpenDetails = input(true); @@ -71,12 +71,12 @@ export class GfAccountsTableComponent { public readonly totalValueInBaseCurrency = input(); public readonly accountDeleted = output(); - public readonly accountToUpdate = output(); + public readonly accountToUpdate = output(); public readonly transferBalance = output(); public readonly sort = viewChild.required(MatSort); - protected readonly dataSource = new MatTableDataSource([]); + protected readonly dataSource = new MatTableDataSource([]); protected readonly displayedColumns = computed(() => { const columns = ['status', 'account', 'platform']; @@ -141,7 +141,9 @@ export class GfAccountsTableComponent { }); } - protected isExcluded(account: Account & { tags?: { id: string }[] }) { + protected isExcluded( + account: AccountWithValue & { tags?: { id: string }[] } + ) { return isAccountExcluded(account); } @@ -173,7 +175,7 @@ export class GfAccountsTableComponent { this.transferBalance.emit(); } - protected onUpdateAccount(aAccount: Account) { + protected onUpdateAccount(aAccount: AccountWithValue) { this.accountToUpdate.emit(aAccount); } } diff --git a/libs/ui/src/lib/activities-table/activities-table.component.stories.ts b/libs/ui/src/lib/activities-table/activities-table.component.stories.ts index 0136545cf..929c71787 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.stories.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.stories.ts @@ -39,7 +39,6 @@ const activities: Activity[] = [ updatedAt: new Date('2025-05-31T18:43:01.840Z'), userId: '081aa387-487d-4438-83a4-3060eb2a016e', account: { - balance: 150.2, comment: null, createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', @@ -105,7 +104,6 @@ const activities: Activity[] = [ updatedAt: new Date('2025-05-31T18:46:14.175Z'), userId: '081aa387-487d-4438-83a4-3060eb2a016e', account: { - balance: 150.2, comment: null, createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', @@ -171,7 +169,6 @@ const activities: Activity[] = [ updatedAt: new Date('2025-05-31T18:49:54.064Z'), userId: '081aa387-487d-4438-83a4-3060eb2a016e', account: { - balance: 150.2, comment: null, createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', @@ -237,7 +234,6 @@ const activities: Activity[] = [ updatedAt: new Date('2025-05-31T18:48:48.209Z'), userId: '081aa387-487d-4438-83a4-3060eb2a016e', account: { - balance: 150.2, comment: null, createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', @@ -303,7 +299,6 @@ const activities: Activity[] = [ updatedAt: new Date('2025-05-31T18:46:44.616Z'), userId: '081aa387-487d-4438-83a4-3060eb2a016e', account: { - balance: 150.2, comment: null, createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', diff --git a/prisma/migrations/20260805120000_removed_balance_from_account/migration.sql b/prisma/migrations/20260805120000_removed_balance_from_account/migration.sql new file mode 100644 index 000000000..2371cb748 --- /dev/null +++ b/prisma/migrations/20260805120000_removed_balance_from_account/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Account" DROP COLUMN "balance"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 77faccd49..4451be4e2 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,7 +27,6 @@ model Access { model Account { activities Order[] - balance Float @default(0) balances AccountBalance[] comment String? createdAt DateTime @default(now()) diff --git a/test/import/not-ok/invalid-platform.json b/test/import/not-ok/invalid-platform.json index 69a8e29ca..d280228b8 100644 --- a/test/import/not-ok/invalid-platform.json +++ b/test/import/not-ok/invalid-platform.json @@ -5,7 +5,6 @@ }, "accounts": [ { - "balance": 0, "balances": [], "currency": "USD", "id": "e62be662-a2c8-4cff-8b79-dc0a46576659", diff --git a/test/import/ok/500-activities.json b/test/import/ok/500-activities.json index 03aabca33..3c74d8517 100644 --- a/test/import/ok/500-activities.json +++ b/test/import/ok/500-activities.json @@ -5,7 +5,6 @@ }, "accounts": [ { - "balance": 2000, "currency": "USD", "id": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", "name": "My Online Trading Account", diff --git a/test/import/ok/derived-currency.json b/test/import/ok/derived-currency.json index 4b7aa46c3..100ab6739 100644 --- a/test/import/ok/derived-currency.json +++ b/test/import/ok/derived-currency.json @@ -5,7 +5,6 @@ }, "accounts": [ { - "balance": 2000, "currency": "USD", "id": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", "name": "My Online Trading Account", diff --git a/test/import/ok/sample.json b/test/import/ok/sample.json index feca8a379..3c75c492b 100644 --- a/test/import/ok/sample.json +++ b/test/import/ok/sample.json @@ -5,7 +5,6 @@ }, "accounts": [ { - "balance": 2000, "balances": [ { "date": "2024-12-31T00:00:00.000Z", From 4386d22e53047e555bbf3ad1600fd78baa0cb46d Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:16:57 +0200 Subject: [PATCH 86/86] Bugfix/percentage values in impersonation mode with unrestricted access (#7522) * Fix percentage values in impersonation mode with unrestricted access * Fix savings rate in impersonation mode * Improve savingsRate on FIRE page * Update changelog --- CHANGELOG.md | 6 ++++ .../src/app/portfolio/portfolio.controller.ts | 30 ++++++++-------- .../src/app/portfolio/portfolio.service.ts | 5 +-- .../redact-values-in-response.interceptor.ts | 2 +- apps/client/src/app/app.component.ts | 10 +++--- .../account-detail-dialog.component.ts | 11 ++++-- .../account-detail-dialog.html | 4 +-- .../interfaces/interfaces.ts | 2 +- .../holding-detail-dialog.html | 4 +-- .../interfaces/interfaces.ts | 2 +- .../pages/accounts/accounts-page.component.ts | 12 ++++--- .../allocations/allocations-page.component.ts | 23 +++++++++---- .../analysis/analysis-page.component.ts | 34 ++++++++++++------- .../portfolio/analysis/analysis-page.html | 12 ++----- .../app/pages/portfolio/fire/fire-page.html | 2 +- .../portfolio-investments.interface.ts | 1 + libs/common/src/lib/permissions.ts | 12 +++---- 17 files changed, 103 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4656bdedf..c32f0535b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Migrated the abstract _Material_ form field from a component to a directive - Removed the redundant `balance` attribute of the account in favor of the account balances +### Fixed + +- Fixed the values of the charts and tables in impersonation mode with an unrestricted access to show absolute values instead of percentages +- Fixed the savings rate of the investment timeline chart and the streaks on the analysis page in impersonation mode to be based on the impersonated user +- Fixed the savings rate of the _FIRE_ calculator in impersonation mode to not be based on the impersonating user + ## 3.43.0 - 2026-08-06 ### Added diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index f6e8648d5..953976a4a 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -136,7 +136,7 @@ export class PortfolioController { if ( hasReadRestrictedAccessPermission({ impersonationId, - user: this.request.user + accesses: this.request.user?.accessesGet }) || isRestrictedView(this.request.user) ) { @@ -180,7 +180,7 @@ export class PortfolioController { hasDetails === false || hasReadRestrictedAccessPermission({ impersonationId, - user: this.request.user + accesses: this.request.user?.accessesGet }) || isRestrictedView(this.request.user) ) { @@ -374,7 +374,7 @@ export class PortfolioController { if ( hasReadRestrictedAccessPermission({ impersonationId, - user: this.request.user + accesses: this.request.user?.accessesGet }) || isRestrictedView(this.request.user) ) { @@ -491,19 +491,19 @@ export class PortfolioController { filterByTags: tags }); - let { investments, streaks } = await this.portfolioService.getInvestments({ - filters, - groupBy, - impersonationId, - dateRange: range, - savingsRate: this.request.user?.settings?.settings.savingsRate, - userId: this.request.user.id - }); + let { investments, savingsRate, streaks } = + await this.portfolioService.getInvestments({ + filters, + groupBy, + impersonationId, + dateRange: range, + userId: this.request.user.id + }); if ( hasReadRestrictedAccessPermission({ impersonationId, - user: this.request.user + accesses: this.request.user?.accessesGet }) || isRestrictedView(this.request.user) ) { @@ -521,6 +521,8 @@ export class PortfolioController { 'currentStreak', 'longestStreak' ]); + + savingsRate = null; } if ( @@ -537,7 +539,7 @@ export class PortfolioController { ]); } - return { investments, streaks }; + return { investments, savingsRate, streaks }; } @Get('performance') @@ -578,7 +580,7 @@ export class PortfolioController { if ( hasReadRestrictedAccessPermission({ impersonationId, - user: this.request.user + accesses: this.request.user?.accessesGet }) || isRestrictedView(this.request.user) || this.request.user.settings.settings.viewMode === 'ZEN' diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index ef79fd717..48ea66dac 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -413,19 +413,18 @@ export class PortfolioService { filters, groupBy, impersonationId, - savingsRate, userId }: { dateRange: DateRange; filters?: Filter[]; groupBy?: GroupBy; impersonationId: string; - savingsRate: number; userId: string; }): Promise { userId = await this.getUserId(impersonationId, userId); const user = await this.userService.user({ id: userId }); const userCurrency = this.getUserCurrency(user); + const savingsRate = (user.settings?.settings as UserSettings)?.savingsRate; const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); @@ -438,6 +437,7 @@ export class PortfolioService { if (activities.length === 0) { return { + savingsRate, investments: [], streaks: { currentStreak: 0, longestStreak: 0 } }; @@ -484,6 +484,7 @@ export class PortfolioService { return { investments, + savingsRate, streaks }; } diff --git a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts index 60b994cac..6a9596298 100644 --- a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts +++ b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts @@ -38,7 +38,7 @@ export class RedactValuesInResponseInterceptor implements NestInterceptor< if ( hasReadRestrictedAccessPermission({ impersonationId, - user + accesses: user?.accessesGet }) || isRestrictedView(user) ) { diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index fd17bcd6e..65b5e95b0 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -57,12 +57,12 @@ export class GfAppComponent implements OnInit { public currentRoute: string; public currentSubRoute: string; public deviceType: string; - public hasImpersonationId: boolean; public hasInfoMessage: boolean; public hasPermissionToChangeDateRange: boolean; public hasPermissionToChangeFilters: boolean; public hasPromotion = false; public hasTabs = false; + public impersonationId: string | null; public info: InfoItem; public pageTitle: string; public routerLinkRegister = publicRoutes.register.routerLink; @@ -116,7 +116,7 @@ export class GfAppComponent implements OnInit { .onChangeHasImpersonation() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { - this.hasImpersonationId = !!impersonationId; + this.impersonationId = impersonationId; }); this.router.events @@ -291,13 +291,12 @@ export class GfAppComponent implements OnInit { baseCurrency: this.user?.settings?.baseCurrency, colorScheme: this.user?.settings?.colorScheme, deviceType: this.deviceType, - hasImpersonationId: this.hasImpersonationId, hasPermissionToAccessAdminControl: hasPermission( this.user?.permissions, permissions.accessAdminControl ), hasPermissionToCreateActivity: - !this.hasImpersonationId && + !this.impersonationId && hasPermission( this.user?.permissions, permissions.createActivity @@ -308,12 +307,13 @@ export class GfAppComponent implements OnInit { permissions.reportDataGlitch ), hasPermissionToUpdateActivity: - !this.hasImpersonationId && + !this.impersonationId && hasPermission( this.user?.permissions, permissions.updateActivity ) && !this.user?.settings?.isRestrictedView, + impersonationId: this.impersonationId, locale: this.user?.settings?.locale }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', 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 e81b8cf06..a0350ee6b 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 @@ -14,7 +14,11 @@ import { PortfolioPosition, User } from '@ghostfolio/common/interfaces'; -import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { + hasPermission, + hasReadRestrictedAccessPermission, + permissions +} from '@ghostfolio/common/permissions'; import { GfAccountBalancesComponent } from '@ghostfolio/ui/account-balances'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfDialogFooterComponent } from '@ghostfolio/ui/dialog-footer'; @@ -225,7 +229,10 @@ export class GfAccountDetailDialogComponent implements OnInit { protected showValuesInPercentage() { return ( - this.data.hasImpersonationId || this.user?.settings?.isRestrictedView + hasReadRestrictedAccessPermission({ + accesses: this.user?.access, + impersonationId: this.data.impersonationId + }) || this.user?.settings?.isRestrictedView ); } 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 485af7500..cb3246c00 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 @@ -158,8 +158,8 @@ [pageSize]="pageSize" [showAccountColumn]="false" [showActions]=" - !data.hasImpersonationId && data.hasPermissionToCreateActivity && + !data.impersonationId && user?.settings?.isExperimentalFeatures && !user?.settings?.isRestrictedView " @@ -183,8 +183,8 @@ [currentBalance]="balance" [locale]="user?.settings?.locale" [showActions]=" - !data.hasImpersonationId && hasPermissionToDeleteAccountBalance && + !data.impersonationId && !user.settings.isRestrictedView " (accountBalanceCreated)="onAddAccountBalance($event)" diff --git a/apps/client/src/app/components/account-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/account-detail-dialog/interfaces/interfaces.ts index 2f80dac36..0e7d04f2c 100644 --- a/apps/client/src/app/components/account-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/account-detail-dialog/interfaces/interfaces.ts @@ -1,8 +1,8 @@ export interface AccountDetailDialogParams { accountId: string; deviceType: string; - hasImpersonationId: boolean; hasPermissionToCreateActivity: boolean; + impersonationId: string | null; } export interface AccountDetailDialogResult { diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index eccc62b4c..8292ff598 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -382,7 +382,7 @@ [hasPermissionToCreateActivity]="false" [hasPermissionToDeleteActivity]="false" [hasPermissionToExportActivities]=" - !data.hasImpersonationId && !user?.settings?.isRestrictedView + !data.impersonationId && !user?.settings?.isRestrictedView " [hasPermissionToFilter]="false" [hasPermissionToOpenDetails]="false" @@ -390,8 +390,8 @@ [pageIndex]="pageIndex" [pageSize]="pageSize" [showActions]=" - !data.hasImpersonationId && data.hasPermissionToCreateActivity && + !data.impersonationId && user?.settings?.isExperimentalFeatures && !user?.settings?.isRestrictedView " diff --git a/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts index 40c94ca60..efc10d6ac 100644 --- a/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts @@ -7,11 +7,11 @@ export interface HoldingDetailDialogParams { colorScheme: ColorScheme; dataSource: DataSource; deviceType: string; - hasImpersonationId: boolean; hasPermissionToAccessAdminControl: boolean; hasPermissionToCreateActivity: boolean; hasPermissionToReportDataGlitch: boolean; hasPermissionToUpdateActivity: boolean; + impersonationId: string | null; locale: string; symbol: string; } diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index e45c1d003..9b10fb222 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -51,9 +51,9 @@ import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-ba export class GfAccountsPageComponent implements OnInit { protected accounts: AccountWithValue[]; protected activitiesCount = 0; - protected hasImpersonationId: boolean; protected hasPermissionToCreateAccount: boolean; protected hasPermissionToUpdateAccount: boolean; + protected impersonationId: string | null; protected totalBalanceInBaseCurrency = 0; protected totalValueInBaseCurrency = 0; protected user: User; @@ -104,12 +104,16 @@ export class GfAccountsPageComponent implements OnInit { }); } + protected get hasImpersonationId() { + return !!this.impersonationId; + } + public ngOnInit() { this.impersonationStorageService .onChangeHasImpersonation() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { - this.hasImpersonationId = !!impersonationId; + this.impersonationId = impersonationId; }); this.userService.stateChanged @@ -252,11 +256,11 @@ export class GfAccountsPageComponent implements OnInit { data: { accountId: aAccountId, deviceType: this.deviceType(), - hasImpersonationId: this.hasImpersonationId, hasPermissionToCreateActivity: !this.hasImpersonationId && hasPermission(this.user?.permissions, permissions.createActivity) && - !this.user?.settings?.isRestrictedView + !this.user?.settings?.isRestrictedView, + impersonationId: this.impersonationId }, height: this.deviceType() === 'mobile' ? '98vh' : '80vh', width: this.deviceType() === 'mobile' ? '100vw' : '50rem' diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index 0931578cf..be7d49bea 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -17,7 +17,11 @@ import { PortfolioPosition, User } from '@ghostfolio/common/interfaces'; -import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { + hasPermission, + hasReadRestrictedAccessPermission, + permissions +} from '@ghostfolio/common/permissions'; import { MarketAdvanced } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart'; @@ -85,7 +89,6 @@ export class GfAllocationsPageComponent implements OnInit { protected readonly deviceType = computed( () => this.deviceDetectorService.deviceInfo().deviceType ); - protected hasImpersonationId: boolean; protected holdings: { [symbol: string]: Pick< PortfolioPosition['assetProfile'], @@ -97,6 +100,7 @@ export class GfAllocationsPageComponent implements OnInit { | 'name' > & { etfProvider: string; value: number }; }; + protected impersonationId: string | null; protected isLoading = false; protected markets: PortfolioDetails['markets']; protected marketsAdvanced: { @@ -169,7 +173,7 @@ export class GfAllocationsPageComponent implements OnInit { .onChangeHasImpersonation() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { - this.hasImpersonationId = !!impersonationId; + this.impersonationId = impersonationId; this.changeDetectorRef.markForCheck(); }); @@ -224,7 +228,12 @@ export class GfAllocationsPageComponent implements OnInit { } protected showValuesInPercentage() { - return this.hasImpersonationId || this.user?.settings?.isRestrictedView; + return ( + hasReadRestrictedAccessPermission({ + accesses: this.user?.access, + impersonationId: this.impersonationId + }) || this.user?.settings?.isRestrictedView + ); } private extractCurrency({ @@ -618,11 +627,11 @@ export class GfAllocationsPageComponent implements OnInit { data: { accountId: aAccountId, deviceType: this.deviceType(), - hasImpersonationId: this.hasImpersonationId, hasPermissionToCreateActivity: - !this.hasImpersonationId && + !this.impersonationId && hasPermission(this.user?.permissions, permissions.createActivity) && - !this.user?.settings?.isRestrictedView + !this.user?.settings?.isRestrictedView, + impersonationId: this.impersonationId }, height: this.deviceType() === 'mobile' ? '98vh' : '80vh', width: this.deviceType() === 'mobile' ? '100vw' : '50rem' diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index c2d23dbc6..424f1bf5b 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -16,7 +16,11 @@ import { ToggleOption, User } from '@ghostfolio/common/interfaces'; -import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { + hasPermission, + hasReadRestrictedAccessPermission, + permissions +} from '@ghostfolio/common/permissions'; import type { AiPromptMode, GroupBy } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; @@ -79,8 +83,8 @@ export class GfAnalysisPageComponent implements OnInit { protected bottom3: PortfolioPosition[]; protected dividendsByGroup: InvestmentItem[]; protected readonly dividendTimelineDataLabel = $localize`Dividend`; - protected hasImpersonationId: boolean; protected hasPermissionToReadAiPrompt: boolean; + protected impersonationId: string | null; protected investments: InvestmentItem[]; protected readonly investmentTimelineDataLabel = $localize`Invested Capital`; protected investmentsByGroup: InvestmentItem[]; @@ -100,6 +104,7 @@ export class GfAnalysisPageComponent implements OnInit { protected performanceDataItemsInPercentage: HistoricalDataItem[]; protected readonly portfolioEvolutionDataLabel = $localize`Investment`; protected precision = 2; + protected savingsRatePerMonth: number | undefined; protected streaks: PortfolioInvestmentsResponse['streaks']; protected top3: PortfolioPosition[]; protected unitCurrentStreak: string; @@ -131,18 +136,13 @@ export class GfAnalysisPageComponent implements OnInit { } get savingsRate() { - const savingsRatePerMonth = - this.hasImpersonationId || this.user.settings.isRestrictedView - ? undefined - : this.user?.settings?.savingsRate; - - if (savingsRatePerMonth === undefined) { + if (!this.savingsRatePerMonth) { return undefined; } return this.mode() === 'year' - ? savingsRatePerMonth * 12 - : savingsRatePerMonth; + ? this.savingsRatePerMonth * 12 + : this.savingsRatePerMonth; } public ngOnInit() { @@ -150,7 +150,7 @@ export class GfAnalysisPageComponent implements OnInit { .onChangeHasImpersonation() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { - this.hasImpersonationId = !!impersonationId; + this.impersonationId = impersonationId; this.changeDetectorRef.markForCheck(); }); @@ -241,6 +241,15 @@ export class GfAnalysisPageComponent implements OnInit { }); } + protected showValuesInPercentage() { + return ( + hasReadRestrictedAccessPermission({ + accesses: this.user?.access, + impersonationId: this.impersonationId + }) || this.user?.settings?.isRestrictedView + ); + } + private fetchDividendsAndInvestments() { this.isLoadingDividendTimelineChart = true; this.isLoadingInvestmentTimelineChart = true; @@ -267,8 +276,9 @@ export class GfAnalysisPageComponent implements OnInit { range: this.user?.settings?.dateRange ?? DEFAULT_DATE_RANGE }) .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(({ investments, streaks }) => { + .subscribe(({ investments, savingsRate, streaks }) => { this.investmentsByGroup = investments; + this.savingsRatePerMonth = savingsRate; this.streaks = streaks; this.unitCurrentStreak = this.mode() === 'year' diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index 0fac204f9..82751b882 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -398,9 +398,7 @@ [benchmarkDataLabel]="portfolioEvolutionDataLabel" [currency]="user?.settings?.baseCurrency" [historicalDataItems]="performanceDataItems" - [isInPercentage]=" - hasImpersonationId || user.settings.isRestrictedView - " + [isInPercentage]="showValuesInPercentage()" [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" /> @@ -456,9 +454,7 @@ [benchmarkDataLabel]="investmentTimelineDataLabel" [currency]="user?.settings?.baseCurrency" [groupBy]="mode()" - [isInPercentage]=" - hasImpersonationId || user.settings.isRestrictedView - " + [isInPercentage]="showValuesInPercentage()" [isLoading]="isLoadingInvestmentTimelineChart" [locale]="user?.settings?.locale" [savingsRate]="savingsRate" @@ -493,9 +489,7 @@ [benchmarkDataLabel]="dividendTimelineDataLabel" [currency]="user?.settings?.baseCurrency" [groupBy]="mode()" - [isInPercentage]=" - hasImpersonationId || user.settings.isRestrictedView - " + [isInPercentage]="showValuesInPercentage()" [isLoading]="isLoadingDividendTimelineChart" [locale]="user?.settings?.locale" /> diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.html b/apps/client/src/app/pages/portfolio/fire/fire-page.html index 7315f10cb..13693a15a 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.html +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -21,7 +21,7 @@ [locale]="user?.settings?.locale" [projectedTotalAmount]="user?.settings?.projectedTotalAmount" [retirementDate]="user?.settings?.retirementDate" - [savingsRate]="user?.settings?.savingsRate" + [savingsRate]="hasImpersonationId ? 0 : user?.settings?.savingsRate" [style.opacity]=" user?.subscription?.type === 'Basic' ? '0.67' : 'initial' " diff --git a/libs/common/src/lib/interfaces/responses/portfolio-investments.interface.ts b/libs/common/src/lib/interfaces/responses/portfolio-investments.interface.ts index 6d0d60002..30ac53765 100644 --- a/libs/common/src/lib/interfaces/responses/portfolio-investments.interface.ts +++ b/libs/common/src/lib/interfaces/responses/portfolio-investments.interface.ts @@ -2,5 +2,6 @@ import { InvestmentItem } from '../investment-item.interface'; export interface PortfolioInvestmentsResponse { investments: InvestmentItem[]; + savingsRate?: number; streaks: { currentStreak: number; longestStreak: number }; } diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index 811ded68c..96533a9e7 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -1,6 +1,6 @@ import { UserWithSettings } from '@ghostfolio/common/types'; -import { Role } from '@prisma/client'; +import { Access, Role } from '@prisma/client'; export const permissions = { accessAdminControl: 'accessAdminControl', @@ -198,17 +198,17 @@ export function hasPermission( } export function hasReadRestrictedAccessPermission({ - impersonationId, - user + accesses = [], + impersonationId }: { - impersonationId: string; - user: UserWithSettings; + accesses?: Pick[]; + impersonationId: string | null; }) { if (!impersonationId) { return false; } - const access = user?.accessesGet?.find(({ id }) => { + const access = accesses.find(({ id }) => { return id === impersonationId; });