From f4bad6acafbecfce2fc45760f25f4c24950b7889 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Oct 2025 14:34:45 +0200 Subject: [PATCH 01/38] Bugfix/provide missing locale to rule settings dialog (#5845) * Provide locale to rule settings dialog * Update changelog --- CHANGELOG.md | 6 ++++++ apps/client/src/app/components/rule/rule.component.ts | 2 ++ apps/client/src/app/components/rules/rules.component.html | 1 + apps/client/src/app/components/rules/rules.component.ts | 1 + .../src/app/pages/portfolio/x-ray/x-ray-page.component.html | 2 ++ 5 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d5674673..36c8c3c29 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 + +### Fixed + +- Ensured the locale is available in the settings dialog to customize the rule thresholds of the _X-ray_ page + ## 2.211.0 - 2025-10-25 ### Added diff --git a/apps/client/src/app/components/rule/rule.component.ts b/apps/client/src/app/components/rule/rule.component.ts index ba77ce162..a4e9f4dea 100644 --- a/apps/client/src/app/components/rule/rule.component.ts +++ b/apps/client/src/app/components/rule/rule.component.ts @@ -51,6 +51,7 @@ export class GfRuleComponent implements OnInit { @Input() categoryName: string; @Input() hasPermissionToUpdateUserSettings: boolean; @Input() isLoading: boolean; + @Input() locale: string; @Input() rule: PortfolioReportRule; @Input() settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment']; @@ -82,6 +83,7 @@ export class GfRuleComponent implements OnInit { data: { rule, categoryName: this.categoryName, + locale: this.locale, settings: this.settings } as RuleSettingsDialogParams, width: this.deviceType === 'mobile' ? '100vw' : '50rem' diff --git a/apps/client/src/app/components/rules/rules.component.html b/apps/client/src/app/components/rules/rules.component.html index d0cf7ece5..0c3153c52 100644 --- a/apps/client/src/app/components/rules/rules.component.html +++ b/apps/client/src/app/components/rules/rules.component.html @@ -12,6 +12,7 @@ [hasPermissionToUpdateUserSettings]=" hasPermissionToUpdateUserSettings " + [locale]="locale" [rule]="rule" [settings]="settings?.[rule.key]" (ruleUpdated)="onRuleUpdated($event)" diff --git a/apps/client/src/app/components/rules/rules.component.ts b/apps/client/src/app/components/rules/rules.component.ts index 6379a40fb..80a59740b 100644 --- a/apps/client/src/app/components/rules/rules.component.ts +++ b/apps/client/src/app/components/rules/rules.component.ts @@ -26,6 +26,7 @@ export class GfRulesComponent { @Input() categoryName: string; @Input() hasPermissionToUpdateUserSettings: boolean; @Input() isLoading: boolean; + @Input() locale: string; @Input() rules: PortfolioReportRule[]; @Input() settings: XRayRulesSettings; diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html index d4820b59e..af74137d1 100644 --- a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html @@ -76,6 +76,7 @@ !hasImpersonationId && hasPermissionToUpdateUserSettings " [isLoading]="isLoading" + [locale]="user?.settings?.locale" [rules]="category.rules" [settings]="user?.settings?.xRayRules" (rulesUpdated)="onRulesUpdated($event)" @@ -90,6 +91,7 @@ !hasImpersonationId && hasPermissionToUpdateUserSettings " [isLoading]="isLoading" + [locale]="user?.settings?.locale" [rules]="inactiveRules" [settings]="user?.settings?.xRayRules" (rulesUpdated)="onRulesUpdated($event)" From 54e0f5e4666e24b49dab9f325e4750b9e979633d Mon Sep 17 00:00:00 2001 From: Abhishek Singla Date: Sat, 25 Oct 2025 23:19:21 +0530 Subject: [PATCH 02/38] Feature/extend user detail dialog (#5844) * Extend user detail dialog * Update changelog --- CHANGELOG.md | 4 + .../admin-users/admin-users.component.ts | 5 +- .../interfaces/interfaces.ts | 1 + .../user-detail-dialog.html | 73 ++++++++++++++++++- 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36c8c3c29..692029639 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 + +- Extended the user detail dialog in the users section of the admin control panel + ### Fixed - Ensured the locale is available in the settings dialog to customize the rule thresholds of the _X-ray_ page diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index fce97877b..4c20f3fe9 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -278,9 +278,9 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { }); } - private openUserDetailDialog(userId: string) { + private openUserDetailDialog(aUserId: string) { const userData = this.dataSource.data.find(({ id }) => { - return id === userId; + return id === aUserId; }); if (!userData) { @@ -293,6 +293,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { data: { userData, deviceType: this.deviceType, + hasPermissionForSubscription: this.hasPermissionForSubscription, locale: this.user?.settings?.locale } as UserDetailDialogParams, height: this.deviceType === 'mobile' ? '98vh' : '60vh', diff --git a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts index 81cf84d12..5f3f4b87a 100644 --- a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts @@ -2,6 +2,7 @@ import { AdminUsers } from '@ghostfolio/common/interfaces'; export interface UserDetailDialogParams { deviceType: string; + hasPermissionForSubscription: boolean; locale: string; userData: AdminUsers['users'][0]; } 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 d90a6abf6..6bc468b59 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 @@ -8,9 +8,9 @@
- User ID + + User ID +
Registration Date + Registration Date +
+ +
+
+ + Role + +
+ @if (data.hasPermissionForSubscription) { +
+ + Country + +
+ } +
+ +
+
+ + Accounts + +
+
+ + Activities + +
+
+ + @if (data.hasPermissionForSubscription) { +
+
+ + Engagement per Day + +
+
+ + API Requests Today + +
+
+ }
From 554710840832de15b48d4405d427209859746e04 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 26 Oct 2025 01:19:25 +0700 Subject: [PATCH 03/38] Feature/add close holding button to holding detail dialog (#5832) * Add close holding button to holding detail dialog * Update changelog --- CHANGELOG.md | 1 + .../holding-detail-dialog.component.ts | 34 +++++++++++++++++++ .../holding-detail-dialog.html | 33 ++++++++++++------ 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 692029639..990398b49 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 close holding button to the holding detail dialog - Extended the user detail dialog in the users section of the admin control panel ### Fixed 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 d4c1c59c1..93005c11f 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 @@ -1,3 +1,4 @@ +import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { GfDialogFooterComponent } from '@ghostfolio/client/components/dialog-footer/dialog-footer.component'; import { GfDialogHeaderComponent } from '@ghostfolio/client/components/dialog-header/dialog-header.component'; @@ -57,6 +58,7 @@ import { isUUID } from 'class-validator'; import { format, isSameMonth, isToday, parseISO } from 'date-fns'; import { addIcons } from 'ionicons'; import { + arrowDownCircleOutline, createOutline, flagOutline, readerOutline, @@ -167,6 +169,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { private userService: UserService ) { addIcons({ + arrowDownCircleOutline, createOutline, flagOutline, readerOutline, @@ -557,6 +560,37 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.dialogRef.close(); } + public onCloseHolding() { + const today = new Date(); + + const activity: CreateOrderDto = { + accountId: this.accounts.length === 1 ? this.accounts[0].id : null, + comment: null, + currency: this.SymbolProfile.currency, + dataSource: this.SymbolProfile.dataSource, + date: today.toISOString(), + fee: 0, + quantity: this.quantity, + symbol: this.SymbolProfile.symbol, + tags: this.tags.map(({ id }) => { + return id; + }), + type: 'SELL', + unitPrice: this.marketPrice + }; + + this.dataService + .postOrder(activity) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.router.navigate( + internalRoutes.portfolio.subRoutes.activities.routerLink + ); + + this.dialogRef.close(); + }); + } + public onExport() { const activityIds = this.dataSource.data.map(({ id }) => { return id; 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 298692303..b0e462a96 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 @@ -428,6 +428,29 @@
+ @if (data.hasPermissionToCreateActivity && quantity > 0) { + + } + @if ( + dataSource?.data.length > 0 && + data.hasPermissionToReportDataGlitch === true + ) { + Report Data Glitch... + } @if (data.hasPermissionToAccessAdminControl) { ... } - @if ( - dataSource?.data.length > 0 && - data.hasPermissionToReportDataGlitch === true - ) { - Report Data Glitch... - }
From 6a93d8c050cc6ef10df9c79e794908cc73b18fc8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 20:41:18 +0200 Subject: [PATCH 04/38] Feature/update locales (#5847) * Update locales * Update translations * Update changelog --------- Co-authored-by: github-actions[bot] Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 4 ++ 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.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 | 69 ++++++++++++++++++---- apps/client/src/locales/messages.zh.xlf | 76 +++++++++++++++++++++---- 13 files changed, 789 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 990398b49..1024336b3 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 - Added a close holding button to the holding detail dialog - Extended the user detail dialog in the users section of the admin control panel +### Changed + +- Improved the language localization for German (`de`) + ### Fixed - Ensured the locale is available in the settings dialog to customize the rule thresholds of the _X-ray_ page diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index c68b369d4..d7e986436 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -1366,6 +1366,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Add Platform Afegeix Plataforma @@ -1739,7 +1747,7 @@ Informar d’un Problema amb les Dades apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -2409,10 +2417,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4451,6 +4455,14 @@ 91 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Rendiment absolut dels actius @@ -5112,6 +5124,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Pla gratuït @@ -6565,7 +6585,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6668,6 +6688,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Yes @@ -6679,6 +6707,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6972,6 +7004,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Guides @@ -7110,6 +7150,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key API Key @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Default Market Price @@ -8128,7 +8184,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 2db1d100f..4d7820831 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -633,6 +633,14 @@ 200 + + Activities + Aktivitäten + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Do you really want to delete this user? Möchtest du diesen Benutzer wirklich löschen? @@ -982,7 +990,7 @@ Datenfehler melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -1280,10 +1288,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4313,6 +4317,14 @@ 210 + + User ID + Benutzer ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Kostenlose Nutzung @@ -5771,6 +5783,14 @@ 364 + + Close Holding + Position abschliessen + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Absolute Anlage Performance @@ -6589,7 +6609,7 @@ Inaktiv apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6692,6 +6712,14 @@ 11 + + Role + Rolle + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Ja @@ -6703,6 +6731,10 @@ Accounts Konten + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6996,6 +7028,14 @@ 293 + + Engagement per Day + Engagement pro Tag + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Ratgeber @@ -7134,6 +7174,14 @@ 167 + + Country + Land + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key API-Schlüssel @@ -7282,6 +7330,14 @@ 234 + + API Requests Today + Heutige API Anfragen + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Standardmarktpreis @@ -8128,7 +8184,7 @@ Anlageprofil verwalten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Ø Preis pro Einheit apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registrierungsdatum apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 29746f597..5c064d234 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -618,6 +618,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Do you really want to delete this user? ¿Estás seguro de eliminar este usuario? @@ -967,7 +975,7 @@ Reporta un anomalía de los datos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -1265,10 +1273,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4290,6 +4294,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Plan gratuito @@ -5748,6 +5760,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Rendimiento absoluto de los activos @@ -6566,7 +6586,7 @@ Inactiva apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6669,6 +6689,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes @@ -6680,6 +6708,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6973,6 +7005,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Guías @@ -7111,6 +7151,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key Clave API @@ -7259,6 +7307,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Precio de mercado por defecto @@ -8129,7 +8185,7 @@ Gestionar perfil de activo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8153,7 +8209,7 @@ Precio medio por unidad apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8544,12 +8600,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 9b40a3031..a616256d1 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -825,6 +825,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Do you really want to delete this user? Voulez-vous vraiment supprimer cet·te utilisateur·rice ? @@ -1254,7 +1262,7 @@ Signaler une Erreur de Données apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -1612,10 +1620,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4289,6 +4293,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Plan gratuit @@ -5747,6 +5759,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Performance des Actifs en valeur absolue @@ -6565,7 +6585,7 @@ Inactif apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6668,6 +6688,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Oui @@ -6679,6 +6707,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6972,6 +7004,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Guides @@ -7110,6 +7150,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key Clé API @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Prix du marché par défaut @@ -8128,7 +8184,7 @@ Gérer le profil d’actif apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index f720742c8..f65b225f4 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -618,6 +618,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Do you really want to delete this user? Vuoi davvero eliminare questo utente? @@ -967,7 +975,7 @@ Segnala un’anomalia dei dati apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -1265,10 +1273,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4290,6 +4294,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Piano gratuito @@ -5748,6 +5760,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Rendimento assoluto dell’Asset @@ -6566,7 +6586,7 @@ Inattivo apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6669,6 +6689,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Si @@ -6680,6 +6708,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6973,6 +7005,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Guide @@ -7111,6 +7151,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key API Key @@ -7259,6 +7307,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Prezzo di mercato predefinito @@ -8129,7 +8185,7 @@ Gestisci profilo risorsa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8153,7 +8209,7 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8544,12 +8600,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 869b932aa..adf4bd27b 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -617,6 +617,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Do you really want to delete this user? Wilt je deze gebruiker echt verwijderen? @@ -966,7 +974,7 @@ Gegevensstoring melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -1264,10 +1272,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4289,6 +4293,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Gratis abonnement @@ -5747,6 +5759,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Absolute Activaprestaties @@ -6565,7 +6585,7 @@ Inactief apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6668,6 +6688,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Ja @@ -6679,6 +6707,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6972,6 +7004,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Gidsen @@ -7110,6 +7150,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key API-sleutel @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Standaard Marktprijs @@ -8128,7 +8184,7 @@ Beheer activaprofiel apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Gemiddelde eenheidsprijs apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 87c485b25..378b0a81a 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -1166,6 +1166,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Add Platform Dodaj Platformę @@ -1875,7 +1883,7 @@ Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -2353,10 +2361,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Export Data @@ -4643,6 +4647,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Plan Darmowy @@ -5747,6 +5759,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Łączny wynik aktywów @@ -6565,7 +6585,7 @@ Nieaktywny apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6668,6 +6688,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Tak @@ -6679,6 +6707,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6972,6 +7004,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Poradniki @@ -7110,6 +7150,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key Klucz API @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Domyślna cena rynkowa @@ -8128,7 +8184,7 @@ Zarządzaj profilem aktywów apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Średnia cena jednostkowa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 8d93b9ecb..6a652b5c6 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -697,6 +697,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Do you really want to delete this user? Deseja realmente excluir este utilizador? @@ -1214,7 +1222,7 @@ Dados do Relatório com Problema apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -1608,10 +1616,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Granted Access @@ -4289,6 +4293,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Plano gratuito @@ -5747,6 +5759,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Desempenho absoluto de ativos @@ -6565,7 +6585,7 @@ Inativo apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6668,6 +6688,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Sim @@ -6679,6 +6707,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6972,6 +7004,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Guias @@ -7110,6 +7150,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key Chave de API @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Preço de mercado padrão @@ -8128,7 +8184,7 @@ Gerenciar perfil de ativos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Preço médio unitário apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index fd87792f9..d0dd4191d 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -1078,6 +1078,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Add Platform Platform Ekle @@ -1731,7 +1739,7 @@ Rapor Veri Sorunu apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -4131,6 +4139,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan Ücretsiz Plan @@ -4470,10 +4486,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Export Data @@ -5747,6 +5759,14 @@ 364 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Mutlak Varlık Performansı @@ -6565,7 +6585,7 @@ Pasif apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6668,6 +6688,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Evet @@ -6679,6 +6707,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6972,6 +7004,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Kılavuzlar @@ -7110,6 +7150,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key API Anahtarı @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Varsayılan Piyasa Fiyatı @@ -8128,7 +8184,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index 61c9be112..6698f404a 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -345,6 +345,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -1362,6 +1366,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Add Platform Додати платформу @@ -1875,7 +1887,7 @@ Повідомити про збій даних apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -2625,10 +2637,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Me @@ -4779,6 +4787,14 @@ 91 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance Абсолютна прибутковість активів @@ -4936,7 +4952,7 @@ Неактивний apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -5255,6 +5271,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides Посібники @@ -5786,6 +5810,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + can be used anonymously може використовуватися анонімно @@ -6750,6 +6782,14 @@ 33 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes Так @@ -7166,6 +7206,14 @@ 110 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key Ключ API @@ -7258,6 +7306,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price Default Market Price @@ -8128,7 +8184,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8152,7 +8208,7 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8543,12 +8599,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index b9b3fb451..1fb1b659d 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -1106,6 +1106,13 @@ 200 + + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Add Platform @@ -1747,7 +1754,7 @@ Report Data Glitch apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -2181,10 +2188,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Export Data @@ -4261,6 +4264,13 @@ 210 + + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan @@ -5233,6 +5243,13 @@ 193 + + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance @@ -6000,6 +6017,13 @@ 9 + + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes @@ -6018,7 +6042,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6136,6 +6160,10 @@ Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6361,6 +6389,13 @@ 291 + + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides @@ -6444,6 +6479,13 @@ 26 + + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key @@ -6600,6 +6642,13 @@ 450 + + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price @@ -7358,7 +7407,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -7379,7 +7428,7 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -7723,11 +7772,11 @@ 128 - + Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 90e239595..bb136c783 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -1175,6 +1175,14 @@ 200 + + Activities + Activities + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 61 + + Add Platform 添加平台 @@ -1884,7 +1892,7 @@ 报告数据故障 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 452 + 450 @@ -2362,10 +2370,6 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html 252 - - apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 12 - Export Data @@ -4652,6 +4656,14 @@ 210 + + User ID + User ID + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 12 + + Free Plan 免费计划 @@ -5732,6 +5744,14 @@ 193 + + Close Holding + Close Holding + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + Absolute Asset Performance 绝对资产回报 @@ -6566,7 +6586,7 @@ 非活跃 apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 87 + 88 @@ -6669,6 +6689,14 @@ 11 + + Role + Role + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 31 + + Yes @@ -6680,6 +6708,10 @@ Accounts Accounts + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 51 + libs/ui/src/lib/assistant/assistant.html 84 @@ -6973,6 +7005,14 @@ 293 + + Engagement per Day + Engagement per Day + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 76 + + Guides 指南 @@ -7111,6 +7151,14 @@ 167 + + Country + Country + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 37 + + API Key API 密钥 @@ -7259,6 +7307,14 @@ 234 + + API Requests Today + API Requests Today + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 86 + + Default Market Price 默认市场价格 @@ -8129,7 +8185,7 @@ 管理资产概况 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 465 @@ -8153,7 +8209,7 @@ 平均单位价格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts - 111 + 113 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -8544,12 +8600,12 @@ 128 - + Registration Date Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 22 + 23 From ecc35c9ffaae297e607d650cbe26c54a4fae2430 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 26 Oct 2025 08:59:36 +0100 Subject: [PATCH 05/38] Task/improve typings of dialogs (#5846) * Improve typings --- apps/client/src/app/app.component.ts | 7 +- .../admin-market-data.component.ts | 27 ++++--- .../admin-platform.component.ts | 62 +++++++++------- .../admin-tag/admin-tag.component.ts | 14 +++- .../interfaces/interfaces.ts | 2 +- .../admin-users/admin-users.component.ts | 7 +- .../app/components/header/header.component.ts | 6 +- .../home-watchlist.component.ts | 20 ++--- .../interfaces/interfaces.ts | 5 ++ ...ogin-with-access-token-dialog.component.ts | 4 +- .../src/app/components/rule/rule.component.ts | 7 +- .../user-account-access.component.ts | 15 +++- .../pages/accounts/accounts-page.component.ts | 25 +++++-- .../interfaces/interfaces.ts | 2 +- .../activities/activities-page.component.ts | 73 ++++++++++--------- .../interfaces/interfaces.ts | 1 - .../interfaces/interfaces.ts | 2 +- .../allocations/allocations-page.component.ts | 7 +- .../pages/register/register-page.component.ts | 22 +++--- .../src/app/services/user/user.service.ts | 22 +++--- .../src/lib/benchmark/benchmark.component.ts | 7 +- ...historical-market-data-editor.component.ts | 28 +++---- 22 files changed, 221 insertions(+), 144 deletions(-) create mode 100644 apps/client/src/app/components/login-with-access-token-dialog/interfaces/interfaces.ts diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index bddd7d3da..5ecb7bf8b 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -276,7 +276,10 @@ export class AppComponent implements OnDestroy, OnInit { .subscribe((user) => { this.user = user; - const dialogRef = this.dialog.open(GfHoldingDetailDialogComponent, { + const dialogRef = this.dialog.open< + GfHoldingDetailDialogComponent, + HoldingDetailDialogParams + >(GfHoldingDetailDialogComponent, { autoFocus: false, data: { dataSource, @@ -302,7 +305,7 @@ export class AppComponent implements OnDestroy, OnInit { hasPermission(this.user?.permissions, permissions.updateOrder) && !this.user?.settings?.isRestrictedView, locale: this.user?.settings?.locale - } as HoldingDetailDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); 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 e907f4b03..2b96bda3b 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 @@ -430,7 +430,10 @@ export class GfAdminMarketDataComponent .subscribe((user) => { this.user = user; - const dialogRef = this.dialog.open(GfAssetProfileDialogComponent, { + const dialogRef = this.dialog.open< + GfAssetProfileDialogComponent, + AssetProfileDialogParams + >(GfAssetProfileDialogComponent, { autoFocus: false, data: { dataSource, @@ -438,7 +441,7 @@ export class GfAdminMarketDataComponent colorScheme: this.user?.settings.colorScheme, deviceType: this.deviceType, locale: this.user?.settings?.locale - } as AssetProfileDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); @@ -465,17 +468,17 @@ export class GfAdminMarketDataComponent .subscribe((user) => { this.user = user; - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfCreateAssetProfileDialogComponent, - { - autoFocus: false, - data: { - deviceType: this.deviceType, - locale: this.user?.settings?.locale - } as CreateAssetProfileDialogParams, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + CreateAssetProfileDialogParams + >(GfCreateAssetProfileDialogComponent, { + autoFocus: false, + data: { + deviceType: this.deviceType, + locale: this.user?.settings?.locale + }, + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() diff --git a/apps/client/src/app/components/admin-platform/admin-platform.component.ts b/apps/client/src/app/components/admin-platform/admin-platform.component.ts index 845c7f375..6c95cee0b 100644 --- a/apps/client/src/app/components/admin-platform/admin-platform.component.ts +++ b/apps/client/src/app/components/admin-platform/admin-platform.component.ts @@ -34,6 +34,7 @@ import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject, takeUntil } from 'rxjs'; import { GfCreateOrUpdatePlatformDialogComponent } from './create-or-update-platform-dialog/create-or-update-platform-dialog.component'; +import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform-dialog/interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -153,19 +154,20 @@ export class GfAdminPlatformComponent implements OnInit, OnDestroy { } private openCreatePlatformDialog() { - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfCreateOrUpdatePlatformDialogComponent, - { - data: { - platform: { - name: null, - url: null - } - }, - height: this.deviceType === 'mobile' ? '98vh' : undefined, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + CreateOrUpdatePlatformDialogParams + >(GfCreateOrUpdatePlatformDialogComponent, { + data: { + platform: { + id: null, + name: null, + url: null + } + }, + height: this.deviceType === 'mobile' ? '98vh' : undefined, + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() @@ -191,21 +193,29 @@ export class GfAdminPlatformComponent implements OnInit, OnDestroy { }); } - private openUpdatePlatformDialog({ id, name, url }) { - const dialogRef = this.dialog.open( + private openUpdatePlatformDialog({ + id, + name, + url + }: { + id: string; + name: string; + url: string; + }) { + const dialogRef = this.dialog.open< GfCreateOrUpdatePlatformDialogComponent, - { - data: { - platform: { - id, - name, - url - } - }, - height: this.deviceType === 'mobile' ? '98vh' : undefined, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + CreateOrUpdatePlatformDialogParams + >(GfCreateOrUpdatePlatformDialogComponent, { + data: { + platform: { + id, + name, + url + } + }, + height: this.deviceType === 'mobile' ? '98vh' : undefined, + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.ts b/apps/client/src/app/components/admin-tag/admin-tag.component.ts index de4c8cedc..5552fa01b 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.ts +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.ts @@ -32,6 +32,7 @@ import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject, takeUntil } from 'rxjs'; import { GfCreateOrUpdateTagDialogComponent } from './create-or-update-tag-dialog/create-or-update-tag-dialog.component'; +import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -149,9 +150,13 @@ export class GfAdminTagComponent implements OnInit, OnDestroy { } private openCreateTagDialog() { - const dialogRef = this.dialog.open(GfCreateOrUpdateTagDialogComponent, { + const dialogRef = this.dialog.open< + GfCreateOrUpdateTagDialogComponent, + CreateOrUpdateTagDialogParams + >(GfCreateOrUpdateTagDialogComponent, { data: { tag: { + id: null, name: null } }, @@ -183,8 +188,11 @@ export class GfAdminTagComponent implements OnInit, OnDestroy { }); } - private openUpdateTagDialog({ id, name }) { - const dialogRef = this.dialog.open(GfCreateOrUpdateTagDialogComponent, { + private openUpdateTagDialog({ id, name }: { id: string; name: string }) { + const dialogRef = this.dialog.open< + GfCreateOrUpdateTagDialogComponent, + CreateOrUpdateTagDialogParams + >(GfCreateOrUpdateTagDialogComponent, { data: { tag: { id, diff --git a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/interfaces/interfaces.ts index bd7214786..4b7f83e93 100644 --- a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/interfaces/interfaces.ts @@ -1,5 +1,5 @@ import { Tag } from '@prisma/client'; export interface CreateOrUpdateTagDialogParams { - tag: Tag; + tag: Pick; } diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 4c20f3fe9..fba54b0bb 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -288,14 +288,17 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { return; } - const dialogRef = this.dialog.open(GfUserDetailDialogComponent, { + const dialogRef = this.dialog.open< + GfUserDetailDialogComponent, + UserDetailDialogParams + >(GfUserDetailDialogComponent, { autoFocus: false, data: { userData, deviceType: this.deviceType, hasPermissionForSubscription: this.hasPermissionForSubscription, locale: this.user?.settings?.locale - } as UserDetailDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : '60vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); diff --git a/apps/client/src/app/components/header/header.component.ts b/apps/client/src/app/components/header/header.component.ts index 6e1a909a1..3f011fec4 100644 --- a/apps/client/src/app/components/header/header.component.ts +++ b/apps/client/src/app/components/header/header.component.ts @@ -1,4 +1,5 @@ import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto'; +import { LoginWithAccessTokenDialogParams } from '@ghostfolio/client/components/login-with-access-token-dialog/interfaces/interfaces'; import { GfLoginWithAccessTokenDialogComponent } from '@ghostfolio/client/components/login-with-access-token-dialog/login-with-access-token-dialog.component'; import { LayoutService } from '@ghostfolio/client/core/layout.service'; import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; @@ -271,7 +272,10 @@ export class GfHeaderComponent implements OnChanges { } public openLoginDialog() { - const dialogRef = this.dialog.open(GfLoginWithAccessTokenDialogComponent, { + const dialogRef = this.dialog.open< + GfLoginWithAccessTokenDialogComponent, + LoginWithAccessTokenDialogParams + >(GfLoginWithAccessTokenDialogComponent, { autoFocus: false, data: { accessToken: '', 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 4c0b614c0..ab43e54dd 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 @@ -149,17 +149,17 @@ export class GfHomeWatchlistComponent implements OnDestroy, OnInit { .subscribe((user) => { this.user = user; - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfCreateWatchlistItemDialogComponent, - { - autoFocus: false, - data: { - deviceType: this.deviceType, - locale: this.user?.settings?.locale - } as CreateWatchlistItemDialogParams, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + CreateWatchlistItemDialogParams + >(GfCreateWatchlistItemDialogComponent, { + autoFocus: false, + data: { + deviceType: this.deviceType, + locale: this.user?.settings?.locale + }, + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() diff --git a/apps/client/src/app/components/login-with-access-token-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/login-with-access-token-dialog/interfaces/interfaces.ts new file mode 100644 index 000000000..2fa8b7ea4 --- /dev/null +++ b/apps/client/src/app/components/login-with-access-token-dialog/interfaces/interfaces.ts @@ -0,0 +1,5 @@ +export interface LoginWithAccessTokenDialogParams { + accessToken: string; + hasPermissionToUseSocialLogin: boolean; + title: string; +} diff --git a/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts b/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts index 3812a18b9..aaca03594 100644 --- a/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts +++ b/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts @@ -26,6 +26,8 @@ import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { eyeOffOutline, eyeOutline } from 'ionicons/icons'; +import { LoginWithAccessTokenDialogParams } from './interfaces/interfaces'; + @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ @@ -51,7 +53,7 @@ export class GfLoginWithAccessTokenDialogComponent { public isAccessTokenHidden = true; public constructor( - @Inject(MAT_DIALOG_DATA) public data: any, + @Inject(MAT_DIALOG_DATA) public data: LoginWithAccessTokenDialogParams, public dialogRef: MatDialogRef, private internetIdentityService: InternetIdentityService, private router: Router, diff --git a/apps/client/src/app/components/rule/rule.component.ts b/apps/client/src/app/components/rule/rule.component.ts index a4e9f4dea..5ed39d5be 100644 --- a/apps/client/src/app/components/rule/rule.component.ts +++ b/apps/client/src/app/components/rule/rule.component.ts @@ -79,13 +79,16 @@ export class GfRuleComponent implements OnInit { } public onCustomizeRule(rule: PortfolioReportRule) { - const dialogRef = this.dialog.open(GfRuleSettingsDialogComponent, { + const dialogRef = this.dialog.open< + GfRuleSettingsDialogComponent, + RuleSettingsDialogParams + >(GfRuleSettingsDialogComponent, { data: { rule, categoryName: this.categoryName, locale: this.locale, settings: this.settings - } as RuleSettingsDialogParams, + }, width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); diff --git a/apps/client/src/app/components/user-account-access/user-account-access.component.ts b/apps/client/src/app/components/user-account-access/user-account-access.component.ts index bdb9af6ed..afcb9d9c8 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.component.ts +++ b/apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -31,6 +31,7 @@ import { EMPTY, Subject } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; import { GfCreateOrUpdateAccessDialogComponent } from './create-or-update-access-dialog/create-or-update-access-dialog.component'; +import { CreateOrUpdateAccessDialogParams } from './create-or-update-access-dialog/interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -187,10 +188,15 @@ export class GfUserAccountAccessComponent implements OnDestroy, OnInit { } private openCreateAccessDialog() { - const dialogRef = this.dialog.open(GfCreateOrUpdateAccessDialogComponent, { + const dialogRef = this.dialog.open< + GfCreateOrUpdateAccessDialogComponent, + CreateOrUpdateAccessDialogParams + >(GfCreateOrUpdateAccessDialogComponent, { data: { access: { alias: '', + grantee: null, + id: null, permissions: ['READ_RESTRICTED'], type: 'PRIVATE' } @@ -219,12 +225,15 @@ export class GfUserAccountAccessComponent implements OnDestroy, OnInit { return; } - const dialogRef = this.dialog.open(GfCreateOrUpdateAccessDialogComponent, { + const dialogRef = this.dialog.open< + GfCreateOrUpdateAccessDialogComponent, + CreateOrUpdateAccessDialogParams + >(GfCreateOrUpdateAccessDialogComponent, { data: { access: { alias: access.alias, - id: access.id, grantee: access.grantee === 'Public' ? null : access.grantee, + id: access.id, permissions: access.permissions, type: access.type } 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 f09901e45..3a1616b6f 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -23,6 +23,8 @@ import { EMPTY, Subject, Subscription } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; import { GfCreateOrUpdateAccountDialogComponent } from './create-or-update-account-dialog/create-or-update-account-dialog.component'; +import { CreateOrUpdateAccountDialogParams } from './create-or-update-account-dialog/interfaces/interfaces'; +import { TransferBalanceDialogParams } from './transfer-balance/interfaces/interfaces'; import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-balance-dialog.component'; @Component({ @@ -179,7 +181,10 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { name, platformId }: AccountModel) { - const dialogRef = this.dialog.open(GfCreateOrUpdateAccountDialogComponent, { + const dialogRef = this.dialog.open< + GfCreateOrUpdateAccountDialogComponent, + CreateOrUpdateAccountDialogParams + >(GfCreateOrUpdateAccountDialogComponent, { data: { account: { balance, @@ -227,7 +232,10 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { } private openAccountDetailDialog(aAccountId: string) { - const dialogRef = this.dialog.open(GfAccountDetailDialogComponent, { + const dialogRef = this.dialog.open< + GfAccountDetailDialogComponent, + AccountDetailDialogParams + >(GfAccountDetailDialogComponent, { autoFocus: false, data: { accountId: aAccountId, @@ -237,7 +245,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { !this.hasImpersonationId && hasPermission(this.user?.permissions, permissions.createOrder) && !this.user?.settings?.isRestrictedView - } as AccountDetailDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); @@ -253,12 +261,16 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { } private openCreateAccountDialog() { - const dialogRef = this.dialog.open(GfCreateOrUpdateAccountDialogComponent, { + const dialogRef = this.dialog.open< + GfCreateOrUpdateAccountDialogComponent, + CreateOrUpdateAccountDialogParams + >(GfCreateOrUpdateAccountDialogComponent, { data: { account: { balance: 0, comment: null, currency: this.user?.settings?.baseCurrency, + id: null, isExcluded: false, name: null, platformId: null @@ -295,7 +307,10 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { } private openTransferBalanceDialog() { - const dialogRef = this.dialog.open(GfTransferBalanceDialogComponent, { + const dialogRef = this.dialog.open< + GfTransferBalanceDialogComponent, + TransferBalanceDialogParams + >(GfTransferBalanceDialogComponent, { data: { accounts: this.accounts }, 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 ffe4f14f6..a3e6272f8 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,5 +1,5 @@ import { Account } from '@prisma/client'; export interface CreateOrUpdateAccountDialogParams { - account: Account; + account: Omit; } 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 ce99fbf77..6ee02bd8e 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 @@ -28,6 +28,7 @@ import { Subject, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { GfCreateOrUpdateActivityDialogComponent } from './create-or-update-activity-dialog/create-or-update-activity-dialog.component'; +import { CreateOrUpdateActivityDialogParams } from './create-or-update-activity-dialog/interfaces/interfaces'; import { GfImportActivitiesDialogComponent } from './import-activities-dialog/import-activities-dialog.component'; import { ImportActivitiesDialogParams } from './import-activities-dialog/interfaces/interfaces'; @@ -245,11 +246,14 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { } public onImport() { - const dialogRef = this.dialog.open(GfImportActivitiesDialogComponent, { + const dialogRef = this.dialog.open< + GfImportActivitiesDialogComponent, + ImportActivitiesDialogParams + >(GfImportActivitiesDialogComponent, { data: { deviceType: this.deviceType, user: this.user - } as ImportActivitiesDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : undefined, width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); @@ -268,12 +272,15 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { } public onImportDividends() { - const dialogRef = this.dialog.open(GfImportActivitiesDialogComponent, { + const dialogRef = this.dialog.open< + GfImportActivitiesDialogComponent, + ImportActivitiesDialogParams + >(GfImportActivitiesDialogComponent, { data: { activityTypes: ['DIVIDEND'], deviceType: this.deviceType, user: this.user - } as ImportActivitiesDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : undefined, width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); @@ -306,18 +313,18 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { } public openUpdateActivityDialog(aActivity: Activity) { - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfCreateOrUpdateActivityDialogComponent, - { - data: { - activity: aActivity, - accounts: this.user?.accounts, - user: this.user - }, - height: this.deviceType === 'mobile' ? '98vh' : '80vh', - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + CreateOrUpdateActivityDialogParams + >(GfCreateOrUpdateActivityDialogComponent, { + data: { + activity: aActivity, + accounts: this.user?.accounts, + user: this.user + }, + height: this.deviceType === 'mobile' ? '98vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() @@ -350,26 +357,26 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { .subscribe((user) => { this.updateUser(user); - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfCreateOrUpdateActivityDialogComponent, - { - data: { - accounts: this.user?.accounts, - activity: { - ...aActivity, - accountId: aActivity?.accountId, - date: new Date(), - id: null, - fee: 0, - type: aActivity?.type ?? 'BUY', - unitPrice: null - }, - user: this.user + CreateOrUpdateActivityDialogParams + >(GfCreateOrUpdateActivityDialogComponent, { + data: { + accounts: this.user?.accounts, + activity: { + ...aActivity, + accountId: aActivity?.accountId, + date: new Date(), + id: null, + fee: 0, + type: aActivity?.type ?? 'BUY', + unitPrice: null }, - height: this.deviceType === 'mobile' ? '98vh' : '80vh', - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + user: this.user + }, + height: this.deviceType === 'mobile' ? '98vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() 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 60a39d361..cc454a66a 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 @@ -4,7 +4,6 @@ import { User } from '@ghostfolio/common/interfaces'; import { Account } from '@prisma/client'; export interface CreateOrUpdateActivityDialogParams { - accountId: string; accounts: Account[]; activity: Activity; user: User; diff --git a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/interfaces/interfaces.ts b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/interfaces/interfaces.ts index a2131db88..051345e60 100644 --- a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/interfaces/interfaces.ts @@ -3,7 +3,7 @@ import { User } from '@ghostfolio/common/interfaces'; import { Type } from '@prisma/client'; export interface ImportActivitiesDialogParams { - activityTypes: Type[]; + activityTypes?: Type[]; deviceType: string; user: User; } 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 da909a78d..b4de51701 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 @@ -558,7 +558,10 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { } private openAccountDetailDialog(aAccountId: string) { - const dialogRef = this.dialog.open(GfAccountDetailDialogComponent, { + const dialogRef = this.dialog.open< + GfAccountDetailDialogComponent, + AccountDetailDialogParams + >(GfAccountDetailDialogComponent, { autoFocus: false, data: { accountId: aAccountId, @@ -568,7 +571,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { !this.hasImpersonationId && hasPermission(this.user?.permissions, permissions.createOrder) && !this.user?.settings?.isRestrictedView - } as AccountDetailDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); diff --git a/apps/client/src/app/pages/register/register-page.component.ts b/apps/client/src/app/pages/register/register-page.component.ts index eff4e308b..acf3c40eb 100644 --- a/apps/client/src/app/pages/register/register-page.component.ts +++ b/apps/client/src/app/pages/register/register-page.component.ts @@ -84,18 +84,18 @@ export class GfRegisterPageComponent implements OnDestroy, OnInit { } public openShowAccessTokenDialog() { - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfUserAccountRegistrationDialogComponent, - { - data: { - deviceType: this.deviceType, - needsToAcceptTermsOfService: this.hasPermissionForSubscription - } as UserAccountRegistrationDialogParams, - disableClose: true, - height: this.deviceType === 'mobile' ? '98vh' : undefined, - width: this.deviceType === 'mobile' ? '100vw' : '30rem' - } - ); + UserAccountRegistrationDialogParams + >(GfUserAccountRegistrationDialogComponent, { + data: { + deviceType: this.deviceType, + needsToAcceptTermsOfService: this.hasPermissionForSubscription + }, + disableClose: true, + height: this.deviceType === 'mobile' ? '98vh' : undefined, + width: this.deviceType === 'mobile' ? '100vw' : '30rem' + }); dialogRef .afterClosed() diff --git a/apps/client/src/app/services/user/user.service.ts b/apps/client/src/app/services/user/user.service.ts index f52a52975..bd9d7d04c 100644 --- a/apps/client/src/app/services/user/user.service.ts +++ b/apps/client/src/app/services/user/user.service.ts @@ -116,18 +116,18 @@ export class UserService extends ObservableStore { permissions.enableSubscriptionInterstitial ) ) { - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfSubscriptionInterstitialDialogComponent, - { - autoFocus: false, - data: { - user - } as SubscriptionInterstitialDialogParams, - disableClose: true, - height: this.deviceType === 'mobile' ? '98vh' : '80vh', - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + SubscriptionInterstitialDialogParams + >(GfSubscriptionInterstitialDialogComponent, { + autoFocus: false, + data: { + user + }, + disableClose: true, + height: this.deviceType === 'mobile' ? '98vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() diff --git a/libs/ui/src/lib/benchmark/benchmark.component.ts b/libs/ui/src/lib/benchmark/benchmark.component.ts index 3af9bc674..bb66acba8 100644 --- a/libs/ui/src/lib/benchmark/benchmark.component.ts +++ b/libs/ui/src/lib/benchmark/benchmark.component.ts @@ -155,14 +155,17 @@ export class GfBenchmarkComponent implements OnChanges, OnDestroy { dataSource, symbol }: AssetProfileIdentifier) { - const dialogRef = this.dialog.open(GfBenchmarkDetailDialogComponent, { + const dialogRef = this.dialog.open< + GfBenchmarkDetailDialogComponent, + BenchmarkDetailDialogParams + >(GfBenchmarkDetailDialogComponent, { data: { dataSource, symbol, colorScheme: this.user?.settings?.colorScheme, deviceType: this.deviceType, locale: this.locale - } as BenchmarkDetailDialogParams, + }, height: this.deviceType === 'mobile' ? '98vh' : undefined, width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); diff --git a/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts index 7fbb1e621..002422c57 100644 --- a/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts @@ -199,21 +199,21 @@ export class GfHistoricalMarketDataEditorComponent }) { const marketPrice = this.marketDataByMonth[yearMonth]?.[day]?.marketPrice; - const dialogRef = this.dialog.open( + const dialogRef = this.dialog.open< GfHistoricalMarketDataEditorDialogComponent, - { - data: { - marketPrice, - currency: this.currency, - dataSource: this.dataSource, - dateString: `${yearMonth}-${day}`, - symbol: this.symbol, - user: this.user - } as HistoricalMarketDataEditorDialogParams, - height: this.deviceType === 'mobile' ? '98vh' : '80vh', - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - } - ); + HistoricalMarketDataEditorDialogParams + >(GfHistoricalMarketDataEditorDialogComponent, { + data: { + marketPrice, + currency: this.currency, + dataSource: this.dataSource, + dateString: `${yearMonth}-${day}`, + symbol: this.symbol, + user: this.user + }, + height: this.deviceType === 'mobile' ? '98vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); dialogRef .afterClosed() From 9f36eef39d9cd7c5d5d280713c63620ef5e6819c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:46:44 +0100 Subject: [PATCH 06/38] Task/extend Contributing section in README.md (#5864) * Add GitHub Sponsors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82d5710d1..9f3633f8f 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ Ghostfolio is **100% free** and **open source**. We encourage and support an act Not sure what to work on? We have [some ideas](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22%20no%3Aassignee), even for [newcomers](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22%20no%3Aassignee). Please join the Ghostfolio [Slack](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) channel or post to [@ghostfolio\_](https://x.com/ghostfolio_) on _X_. We would love to hear from you. -If you like to support this project, get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). +If you like to support this project, become a [**Sponsor**](https://github.com/sponsors/ghostfolio), get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). ## Analytics From cf2dd95906870b7359f39bc3f10750db0fab547d Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:47:38 +0100 Subject: [PATCH 07/38] Task/add LambdaTest to Sponsors in README.md (#5861) * Add LambdaTest --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 9f3633f8f..1a5cc6e95 100644 --- a/README.md +++ b/README.md @@ -299,6 +299,17 @@ Not sure what to work on? We have [some ideas](https://github.com/ghostfolio/gho If you like to support this project, become a [**Sponsor**](https://github.com/sponsors/ghostfolio), get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). +## Sponsors + +
+

+ Browser testing via
+ + LambdaTest Logo + +

+
+ ## Analytics ![Alt](https://repobeats.axiom.co/api/embed/281a80b2d0c4af1162866c24c803f1f18e5ed60e.svg 'Repobeats analytics image') From 7dc74fe6812cf1efe85d19f0713e79df06200b8d Mon Sep 17 00:00:00 2001 From: Vansh <140736931+Vansh-Parate@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:40:35 +0530 Subject: [PATCH 08/38] Task/refactor column definitions in AI service (#5834) * Refactor column definitions in AI service * Update changelog --- CHANGELOG.md | 2 + apps/api/src/app/endpoints/ai/ai.service.ts | 79 ++++++++++++++++----- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1024336b3..220b29036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Refactored the generation of the holdings table in the _Copy AI prompt to clipboard for analysis_ action on the analysis page (experimental) +- Refactored the generation of the holdings table in the _Copy portfolio data to clipboard for AI prompt_ action on the analysis page (experimental) - Improved the language localization for German (`de`) ### Fixed diff --git a/apps/api/src/app/endpoints/ai/ai.service.ts b/apps/api/src/app/endpoints/ai/ai.service.ts index 4cc4fde65..d07768d69 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.ts +++ b/apps/api/src/app/endpoints/ai/ai.service.ts @@ -14,6 +14,27 @@ import type { ColumnDescriptor } from 'tablemark'; @Injectable() export class AiService { + private static readonly HOLDINGS_TABLE_COLUMN_DEFINITIONS: ({ + key: + | 'ALLOCATION_PERCENTAGE' + | 'ASSET_CLASS' + | 'ASSET_SUB_CLASS' + | 'CURRENCY' + | 'NAME' + | 'SYMBOL'; + } & ColumnDescriptor)[] = [ + { key: 'NAME', name: 'Name' }, + { key: 'SYMBOL', name: 'Symbol' }, + { key: 'CURRENCY', name: 'Currency' }, + { key: 'ASSET_CLASS', name: 'Asset Class' }, + { key: 'ASSET_SUB_CLASS', name: 'Asset Sub Class' }, + { + align: 'right', + key: 'ALLOCATION_PERCENTAGE', + name: 'Allocation in Percentage' + } + ]; + public constructor( private readonly portfolioService: PortfolioService, private readonly propertyService: PropertyService @@ -59,14 +80,10 @@ export class AiService { userId }); - const holdingsTableColumns: ColumnDescriptor[] = [ - { name: 'Name' }, - { name: 'Symbol' }, - { name: 'Currency' }, - { name: 'Asset Class' }, - { name: 'Asset Sub Class' }, - { align: 'right', name: 'Allocation in Percentage' } - ]; + const holdingsTableColumns: ColumnDescriptor[] = + AiService.HOLDINGS_TABLE_COLUMN_DEFINITIONS.map(({ align, name }) => { + return { name, align: align ?? 'left' }; + }); const holdingsTableRows = Object.values(holdings) .sort((a, b) => { @@ -78,17 +95,45 @@ export class AiService { assetClass, assetSubClass, currency, - name, + name: label, symbol }) => { - return { - Name: name, - Symbol: symbol, - Currency: currency, - 'Asset Class': assetClass ?? '', - 'Asset Sub Class': assetSubClass ?? '', - 'Allocation in Percentage': `${(allocationInPercentage * 100).toFixed(3)}%` - }; + return AiService.HOLDINGS_TABLE_COLUMN_DEFINITIONS.reduce( + (row, { key, name }) => { + switch (key) { + case 'ALLOCATION_PERCENTAGE': + row[name] = `${(allocationInPercentage * 100).toFixed(3)}%`; + break; + + case 'ASSET_CLASS': + row[name] = assetClass ?? ''; + break; + + case 'ASSET_SUB_CLASS': + row[name] = assetSubClass ?? ''; + break; + + case 'CURRENCY': + row[name] = currency; + break; + + case 'NAME': + row[name] = label; + break; + + case 'SYMBOL': + row[name] = symbol; + break; + + default: + row[name] = ''; + break; + } + + return row; + }, + {} as Record + ); } ); From 8bd47d3f7c6db67d90f997f04ece134c5bf876a9 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:30:39 +0100 Subject: [PATCH 09/38] Feature/set up sponsors section on about page (#5862) * Set up sponsors section * Update changelog --- CHANGELOG.md | 1 + .../about/overview/about-overview-page.html | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 220b29036..ad8f2f70e 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 a close holding button to the holding detail dialog +- Added the _Sponsors_ section to the about page - Extended the user detail dialog in the users section of the admin control panel ### Changed diff --git a/apps/client/src/app/pages/about/overview/about-overview-page.html b/apps/client/src/app/pages/about/overview/about-overview-page.html index 4085498a9..72c054170 100644 --- a/apps/client/src/app/pages/about/overview/about-overview-page.html +++ b/apps/client/src/app/pages/about/overview/about-overview-page.html @@ -175,7 +175,7 @@ -
+
}
+ +
+
+

Sponsors

+
+ Browser testing via +
+ + LambdaTest Logo + +
+
+
From 8c80086da168f9eaf5be240852ba3a2656729bdd Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:31:16 +0100 Subject: [PATCH 10/38] Bugfix/fix typography hierarchy in resources pages (#5863) * Fix hierarchy --- .../glossary/resources-glossary.component.html | 18 +++++++++--------- .../guides/resources-guides.component.html | 4 ++-- .../markets/resources-markets.component.html | 8 ++++---- .../overview/resources-overview.component.html | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html index b65054bba..fa74cd084 100644 --- a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html +++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.html @@ -5,7 +5,7 @@
-

Buy and Hold

+

Buy and Hold

Buy and hold is a passive investment strategy where you buy assets and hold them for a long period regardless of fluctuations in the @@ -22,7 +22,7 @@
-

Deflation

+

Deflation

Deflation is a decrease of the general price level for goods and services in an economy over a period of time. @@ -38,7 +38,7 @@
-

Dollar-Cost Averaging (DCA)

+

Dollar-Cost Averaging (DCA)

Dollar-cost averaging is an investment strategy where you split the total amount to be invested across periodic purchases of a @@ -56,7 +56,7 @@
-

Financial Independence

+

Financial Independence

Financial independence is the status of having enough income, for example with a passive income like dividends, to cover your living @@ -73,7 +73,7 @@
-

FIRE

+

FIRE

FIRE is a movement that promotes saving and investing to achieve financial independence and early retirement. @@ -85,7 +85,7 @@
-

Inflation

+

Inflation

Inflation is an increase of the general price level for goods and services in an economy over a period of time. @@ -102,7 +102,7 @@ @if (hasPermissionForSubscription) {
-

Personal Finance Tools

+

Personal Finance Tools

Personal finance tools are software applications that help manage your money, track expenses, set budgets, monitor @@ -118,7 +118,7 @@ }
-

Stagflation

+

Stagflation

Stagflation describes a situation in which there is a stagnant economy with high unemployment and high inflation. @@ -134,7 +134,7 @@
-

Stealth Wealth

+

Stealth Wealth

Stealth wealth is a lifestyle choice where you don’t openly show off your wealth, but instead live quietly to maintain privacy and diff --git a/apps/client/src/app/pages/resources/guides/resources-guides.component.html b/apps/client/src/app/pages/resources/guides/resources-guides.component.html index 3bd8efec6..54b3d1f3e 100644 --- a/apps/client/src/app/pages/resources/guides/resources-guides.component.html +++ b/apps/client/src/app/pages/resources/guides/resources-guides.component.html @@ -5,7 +5,7 @@
-

Boringly Getting Rich

+

Boringly Getting Rich

The Boringly Getting Rich guide supports you to get started with investing. It introduces a strategy utilizing a broadly @@ -21,7 +21,7 @@
-

How do I get my finances in order?

+

How do I get my finances in order?

Before you can think of long-term investing, you have to get your finances in order. Learn how you can reach your financial goals diff --git a/apps/client/src/app/pages/resources/markets/resources-markets.component.html b/apps/client/src/app/pages/resources/markets/resources-markets.component.html index 74d4bb82b..ce780aedf 100644 --- a/apps/client/src/app/pages/resources/markets/resources-markets.component.html +++ b/apps/client/src/app/pages/resources/markets/resources-markets.component.html @@ -3,7 +3,7 @@
-

Crypto Coins Heatmap

+

Crypto Coins Heatmap

With the Crypto Coins Heatmap you can track the daily market movements of cryptocurrencies as a visual snapshot. @@ -17,7 +17,7 @@
-

Fear & Greed Index

+

Fear & Greed Index

The fear and greed index was developed by CNNMoney to measure the primary emotions (fear and greed) that influence how much @@ -32,7 +32,7 @@
-

Inflation Chart

+

Inflation Chart

Inflation Chart helps you find the intrinsic value of stock markets, stock prices, goods and services by adjusting them to the @@ -48,7 +48,7 @@
-

Stock Heatmap

+

Stock Heatmap

With the Stock Heatmap you can track the daily market movements of stocks as a visual snapshot. diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.html b/apps/client/src/app/pages/resources/overview/resources-overview.component.html index 39d7c1e62..3a6f18d40 100644 --- a/apps/client/src/app/pages/resources/overview/resources-overview.component.html +++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -5,7 +5,7 @@
@for (item of overviewItems; track item) {
-

{{ item.title }}

+

{{ item.title }}

{{ item.description }}

Explore {{ item.title }} →
From ed115c59b14cfd0cc69dd9060d91938c0d98e6f1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Oct 2025 17:30:09 +0100 Subject: [PATCH 11/38] Feature/improve usability of user detail dialog (#5868) * Do not reload on close * Update changelog --- CHANGELOG.md | 1 + .../src/app/components/admin-users/admin-users.component.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad8f2f70e..24103d37d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Refactored the generation of the holdings table in the _Copy AI prompt to clipboard for analysis_ action on the analysis page (experimental) - Refactored the generation of the holdings table in the _Copy portfolio data to clipboard for AI prompt_ action on the analysis page (experimental) +- Improved the usability of the user detail dialog in the users section of the admin control panel - Improved the language localization for German (`de`) ### Fixed diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index fba54b0bb..c0d058ad2 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -307,7 +307,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { - this.fetchUsers(); this.router.navigate(['.'], { relativeTo: this.route }); }); } From aa8f933110316943b394ff4573461d4740df210a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 29 Oct 2025 17:33:22 +0100 Subject: [PATCH 12/38] Release 2.212.0 (#5871) --- 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 24103d37d..8245505b5 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 +## 2.212.0 - 2025-10-29 ### Added diff --git a/package-lock.json b/package-lock.json index 62913d174..50138c7c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.211.0", + "version": "2.212.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.211.0", + "version": "2.212.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 512f61b6d..d7b626f85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.211.0", + "version": "2.212.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 0ea2edd1e55015f086ee081bac53910d2991b03d Mon Sep 17 00:00:00 2001 From: David Requeno <108202767+DavidReque@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:28:46 -0600 Subject: [PATCH 13/38] Feature/extend menu in activities table component (#5855) * Extend menu in activities table component * Update changelog --- CHANGELOG.md | 6 +++++ .../activities-table.component.html | 14 +++++++----- .../activities-table.component.ts | 22 ++++++++++++------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8245505b5..d0f90277e 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 + +- Extended the activities table menu with a _View Holding_ item + ## 2.212.0 - 2025-10-29 ### Added 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 843832e1a..e230c0bcd 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -437,6 +437,14 @@ class="no-max-width" xPosition="before" > + @if (canClickActivity(element)) { + + }
-
-
-

Sponsors

-
- Browser testing via -
- - LambdaTest Logo - + @if (user?.subscription?.type !== 'Premium') { +
+
+

Sponsors

+
+ Browser testing via +
+ + LambdaTest Logo + +
-
+ }
From f188d1b2ab87b1a3bbe9eb45be21968e95ee32be Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Oct 2025 19:16:15 +0100 Subject: [PATCH 23/38] Feature/update OSS friends 20251031 (#5879) * Update OSS friends --- apps/client/src/assets/oss-friends.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/client/src/assets/oss-friends.json b/apps/client/src/assets/oss-friends.json index 827b56c3a..2fbf5e27d 100644 --- a/apps/client/src/assets/oss-friends.json +++ b/apps/client/src/assets/oss-friends.json @@ -1,5 +1,5 @@ { - "createdAt": "2025-09-17T00:00:00.000Z", + "createdAt": "2025-10-31T00:00:00.000Z", "data": [ { "name": "Activepieces", @@ -16,6 +16,11 @@ "description": "Argos provides the developer tools to debug tests and detect visual regressions.", "href": "https://argos-ci.com" }, + { + "name": "Bifrost", + "description": "Fastest LLM gateway with adaptive load balancer, cluster mode, guardrails, 1000+ models support & <100 µs overhead at 5k RPS.", + "href": "https://www.getmaxim.ai/bifrost" + }, { "name": "Cal.com", "description": "Cal.com is a scheduling tool that helps you schedule meetings without the back-and-forth emails.", @@ -56,11 +61,6 @@ "description": "Inbox Zero makes it easy to clean up your inbox and reach inbox zero fast. It provides bulk newsletter unsubscribe, cold email blocking, email analytics, and AI automations.", "href": "https://getinboxzero.com" }, - { - "name": "Infisical", - "description": "Open source, end-to-end encrypted platform that lets you securely manage secrets and configs across your team, devices, and infrastructure.", - "href": "https://infisical.com" - }, { "name": "KeepHQ", "description": "Keep is an open-source AIOps (AI for IT operations) platform", From 6177ec0ec57ed60a089efc97739583088efe332e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 31 Oct 2025 19:18:21 +0100 Subject: [PATCH 24/38] Feature/improve icon of View Holding menu item in activities table (#5881) * Improve icon * Update changelog --- CHANGELOG.md | 1 + .../lib/activities-table/activities-table.component.html | 2 +- .../lib/activities-table/activities-table.component.ts | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2417d3dcc..71370cd35 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 icon of the _View Holding_ menu item in the activities table - Refreshed the cryptocurrencies list ## 2.213.0 - 2025-10-30 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 e230c0bcd..46e1de875 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -440,7 +440,7 @@ @if (canClickActivity(element)) { 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 0b58bda94..1313ef1e2 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -56,8 +56,8 @@ import { documentTextOutline, ellipsisHorizontal, ellipsisVertical, - trashOutline, - walletOutline + tabletLandscapeOutline, + trashOutline } from 'ionicons/icons'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject, Subscription, takeUntil } from 'rxjs'; @@ -154,8 +154,8 @@ export class GfActivitiesTableComponent documentTextOutline, ellipsisHorizontal, ellipsisVertical, - trashOutline, - walletOutline + tabletLandscapeOutline, + trashOutline }); } From b705b8f07b8dc3443300af8af925969f9cabbae6 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:07:03 +0700 Subject: [PATCH 25/38] Task/resolve @typescript-eslint/prefer-regexp-exec ESLint rule (#5885) * fix(lint): remove @typescript-eslint/prefer-regexp-exec override * fix(lint): resolve eslint errors --- apps/api/src/services/i18n/i18n.service.ts | 2 +- eslint.config.cjs | 3 +-- libs/common/src/lib/helper.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/api/src/services/i18n/i18n.service.ts b/apps/api/src/services/i18n/i18n.service.ts index 0f1f6239d..cf340d7c6 100644 --- a/apps/api/src/services/i18n/i18n.service.ts +++ b/apps/api/src/services/i18n/i18n.service.ts @@ -65,7 +65,7 @@ export class I18nService { } private parseLanguageCode(aFileName: string) { - const match = aFileName.match(/\.([a-zA-Z]+)\.xlf$/); + const match = /\.([a-zA-Z]+)\.xlf$/.exec(aFileName); return match ? match[1] : DEFAULT_LANGUAGE_CODE; } diff --git a/eslint.config.cjs b/eslint.config.cjs index c7e08821c..7907f4bce 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -189,8 +189,7 @@ module.exports = [ // The following rules are part of @typescript-eslint/stylistic-type-checked // and can be remove once solved - '@typescript-eslint/prefer-nullish-coalescing': 'warn', // TODO: Requires strictNullChecks: true - '@typescript-eslint/prefer-regexp-exec': 'warn' + '@typescript-eslint/prefer-nullish-coalescing': 'warn' // TODO: Requires strictNullChecks: true } })) ]; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 97b762267..7452b604c 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -375,7 +375,7 @@ export function parseDate(date: string): Date { // Transform 'yyyyMMdd' format to supported format by parse function if (date?.length === 8) { - const match = date.match(/^(\d{4})(\d{2})(\d{2})$/); + const match = /^(\d{4})(\d{2})(\d{2})$/.exec(date); if (match) { const [, year, month, day] = match; From debadd455ea4f14b8e00965721ced1ed5a39973b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 09:44:21 +0100 Subject: [PATCH 26/38] Task/upgrade ng-extract-i18n-merge to version 3.1.0 (#5886) * Upgrade ng-extract-i18n-merge to version 3.1.0 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71370cd35..248aaa6ac 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 - Improved the icon of the _View Holding_ menu item in the activities table - Refreshed the cryptocurrencies list +- Upgraded `ng-extract-i18n-merge` from version `3.0.0` to `3.1.0` ## 2.213.0 - 2025-10-30 diff --git a/package-lock.json b/package-lock.json index b306692a3..914a783e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,7 +77,7 @@ "lodash": "4.17.21", "marked": "15.0.4", "ms": "3.0.0-canary.1", - "ng-extract-i18n-merge": "3.0.0", + "ng-extract-i18n-merge": "3.1.0", "ngx-device-detector": "10.1.0", "ngx-markdown": "20.0.0", "ngx-skeleton-loader": "11.3.0", @@ -32780,9 +32780,9 @@ "license": "MIT" }, "node_modules/ng-extract-i18n-merge": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ng-extract-i18n-merge/-/ng-extract-i18n-merge-3.0.0.tgz", - "integrity": "sha512-vTWtAz6a/wVYxnUMFHp1ur6o4JSLm+LcxdSMV8o8Ml2p5oCsSB4iFd5E6h8Yb8X8D596qyBz0ELgiDmbn4YyRQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ng-extract-i18n-merge/-/ng-extract-i18n-merge-3.1.0.tgz", + "integrity": "sha512-4rJRcpTcP54xf5cjoz3S1By0T04X2RoyQcMDxr4wLdRx3fVxkeP8jeuLzmj9F4G5n0yMQb+6jhUiFERxpkfs1w==", "license": "MIT", "dependencies": { "@angular-devkit/architect": "^0.2000.0", diff --git a/package.json b/package.json index cbbb12652..43970a7f0 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "lodash": "4.17.21", "marked": "15.0.4", "ms": "3.0.0-canary.1", - "ng-extract-i18n-merge": "3.0.0", + "ng-extract-i18n-merge": "3.1.0", "ngx-device-detector": "10.1.0", "ngx-markdown": "20.0.0", "ngx-skeleton-loader": "11.3.0", From 4ecfdadda448d681fb8d6c16deb56d1d566493e5 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 1 Nov 2025 23:59:59 +0700 Subject: [PATCH 27/38] Task/resolve @typescript-eslint/no-unsafe-function-type ESLint rule (#5889) * fix(lint): remove @typescript-eslint/no-unsafe-function-type override * fix(lint): resolve eslint errors --- apps/api/src/app/auth/google.strategy.ts | 3 ++- apps/client/src/app/core/module-preload.service.ts | 2 +- eslint.config.cjs | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/api/src/app/auth/google.strategy.ts b/apps/api/src/app/auth/google.strategy.ts index 02f82a7a8..3e4b4ca0d 100644 --- a/apps/api/src/app/auth/google.strategy.ts +++ b/apps/api/src/app/auth/google.strategy.ts @@ -3,6 +3,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con import { Injectable, Logger } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Provider } from '@prisma/client'; +import { DoneCallback } from 'passport'; import { Profile, Strategy } from 'passport-google-oauth20'; import { AuthService } from './auth.service'; @@ -29,7 +30,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { _token: string, _refreshToken: string, profile: Profile, - done: Function + done: DoneCallback ) { try { const jwt = await this.authService.validateOAuthLogin({ diff --git a/apps/client/src/app/core/module-preload.service.ts b/apps/client/src/app/core/module-preload.service.ts index fcba48c52..85d9c5e33 100644 --- a/apps/client/src/app/core/module-preload.service.ts +++ b/apps/client/src/app/core/module-preload.service.ts @@ -7,7 +7,7 @@ export class ModulePreloadService implements PreloadingStrategy { /** * Preloads all lazy loading modules with the attribute 'preload' set to true */ - preload(route: Route, load: Function): Observable { + preload(route: Route, load: () => Observable): Observable { return route.data?.preload ? load() : of(null); } } diff --git a/eslint.config.cjs b/eslint.config.cjs index 7907f4bce..cb586e8ed 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -170,7 +170,6 @@ module.exports = [ '@typescript-eslint/no-unsafe-argument': 'warn', '@typescript-eslint/no-unsafe-assignment': 'warn', '@typescript-eslint/no-unsafe-enum-comparison': 'warn', - '@typescript-eslint/no-unsafe-function-type': 'warn', '@typescript-eslint/no-unsafe-member-access': 'warn', '@typescript-eslint/no-unsafe-return': 'warn', '@typescript-eslint/no-unsafe-call': 'warn', From 60bfe1eaa6b0c08ea6235136ffa175c800e3b251 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:01:24 +0700 Subject: [PATCH 28/38] Task/resolve no-constant-binary-expression ESLint rule (#5890) * fix(lint): remove no-constant-binary-expression override * fix(lint): resolve eslint errors --- eslint.config.cjs | 1 - libs/ui/src/lib/fire-calculator/fire-calculator.component.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/eslint.config.cjs b/eslint.config.cjs index cb586e8ed..a88d0cc85 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -152,7 +152,6 @@ module.exports = [ // The following rules are part of eslint:recommended // and can be remove once solved - 'no-constant-binary-expression': 'warn', 'no-loss-of-precision': 'warn', // The following rules are part of @typescript-eslint/recommended-type-checked diff --git a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts index df7ca79fa..44276ec43 100644 --- a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts +++ b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -185,7 +185,7 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy { 'principalInvestmentAmount' ).value, projectedTotalAmount: - Number(this.getProjectedTotalAmount().toFixed(0)) ?? 0, + Math.round(this.getProjectedTotalAmount()) || 0, retirementDate: this.getRetirementDate() ?? this.DEFAULT_RETIREMENT_DATE }, From e5550a432222c6ce03cdea6562fb177fd031c4bf Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:02:37 +0100 Subject: [PATCH 29/38] Task/extend user settings in test files (#5836) * Extend user settings by performance calculation type --- test/import/not-ok/invalid-data-source.json | 8 +++++++- test/import/not-ok/invalid-date-before-min.json | 8 +++++++- test/import/not-ok/invalid-date.json | 8 +++++++- test/import/not-ok/invalid-symbol.json | 8 +++++++- test/import/not-ok/invalid-type.json | 8 +++++++- test/import/not-ok/unavailable-exchange-rate.json | 8 +++++++- test/import/ok/500-activities.json | 3 ++- test/import/ok/btceur.json | 3 ++- test/import/ok/btcusd-short.json | 3 ++- test/import/ok/btcusd.json | 3 ++- test/import/ok/derived-currency.json | 3 ++- test/import/ok/novn-buy-and-sell-partially.json | 3 ++- test/import/ok/novn-buy-and-sell.json | 3 ++- test/import/ok/penthouse-apartment.json | 3 ++- test/import/ok/sample.json | 3 ++- test/import/ok/vti-buy-long-history.json | 3 ++- test/import/ok/without-accounts.json | 3 ++- 17 files changed, 64 insertions(+), 17 deletions(-) diff --git a/test/import/not-ok/invalid-data-source.json b/test/import/not-ok/invalid-data-source.json index 472e295ee..f8e920c67 100644 --- a/test/import/not-ok/invalid-data-source.json +++ b/test/import/not-ok/invalid-data-source.json @@ -14,5 +14,11 @@ "type": "BUY", "unitPrice": 100.0 } - ] + ], + "user": { + "settings": { + "currency": "USD", + "performanceCalculationType": "ROAI" + } + } } diff --git a/test/import/not-ok/invalid-date-before-min.json b/test/import/not-ok/invalid-date-before-min.json index 3040581b2..260d79166 100644 --- a/test/import/not-ok/invalid-date-before-min.json +++ b/test/import/not-ok/invalid-date-before-min.json @@ -14,5 +14,11 @@ "type": "BUY", "unitPrice": 100.0 } - ] + ], + "user": { + "settings": { + "currency": "USD", + "performanceCalculationType": "ROAI" + } + } } diff --git a/test/import/not-ok/invalid-date.json b/test/import/not-ok/invalid-date.json index 99cd6d156..4522c6dcc 100644 --- a/test/import/not-ok/invalid-date.json +++ b/test/import/not-ok/invalid-date.json @@ -14,5 +14,11 @@ "type": "BUY", "unitPrice": 100.0 } - ] + ], + "user": { + "settings": { + "currency": "USD", + "performanceCalculationType": "ROAI" + } + } } diff --git a/test/import/not-ok/invalid-symbol.json b/test/import/not-ok/invalid-symbol.json index 14f0051ec..0bbbf53db 100644 --- a/test/import/not-ok/invalid-symbol.json +++ b/test/import/not-ok/invalid-symbol.json @@ -14,5 +14,11 @@ "type": "BUY", "unitPrice": 100.0 } - ] + ], + "user": { + "settings": { + "currency": "USD", + "performanceCalculationType": "ROAI" + } + } } diff --git a/test/import/not-ok/invalid-type.json b/test/import/not-ok/invalid-type.json index a23f72411..a8967d81a 100644 --- a/test/import/not-ok/invalid-type.json +++ b/test/import/not-ok/invalid-type.json @@ -14,5 +14,11 @@ "type": "", "unitPrice": 100.0 } - ] + ], + "user": { + "settings": { + "currency": "USD", + "performanceCalculationType": "ROAI" + } + } } diff --git a/test/import/not-ok/unavailable-exchange-rate.json b/test/import/not-ok/unavailable-exchange-rate.json index 4d8be156a..66c7044d7 100644 --- a/test/import/not-ok/unavailable-exchange-rate.json +++ b/test/import/not-ok/unavailable-exchange-rate.json @@ -15,5 +15,11 @@ "date": "1990-01-01T00:00:00.000Z", "symbol": "MSFT" } - ] + ], + "user": { + "settings": { + "currency": "USD", + "performanceCalculationType": "ROAI" + } + } } diff --git a/test/import/ok/500-activities.json b/test/import/ok/500-activities.json index b691a6f9f..2793c695e 100644 --- a/test/import/ok/500-activities.json +++ b/test/import/ok/500-activities.json @@ -6019,7 +6019,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/btceur.json b/test/import/ok/btceur.json index b370682f9..ae9eb8921 100644 --- a/test/import/ok/btceur.json +++ b/test/import/ok/btceur.json @@ -23,7 +23,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/btcusd-short.json b/test/import/ok/btcusd-short.json index bc4152de9..6f25a7740 100644 --- a/test/import/ok/btcusd-short.json +++ b/test/import/ok/btcusd-short.json @@ -36,7 +36,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/btcusd.json b/test/import/ok/btcusd.json index fc2e1f66e..4a85f967e 100644 --- a/test/import/ok/btcusd.json +++ b/test/import/ok/btcusd.json @@ -23,7 +23,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/derived-currency.json b/test/import/ok/derived-currency.json index e740c1ae3..637ab21b6 100644 --- a/test/import/ok/derived-currency.json +++ b/test/import/ok/derived-currency.json @@ -31,7 +31,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/novn-buy-and-sell-partially.json b/test/import/ok/novn-buy-and-sell-partially.json index 8c5778566..3bdd7eb7e 100644 --- a/test/import/ok/novn-buy-and-sell-partially.json +++ b/test/import/ok/novn-buy-and-sell-partially.json @@ -27,7 +27,8 @@ ], "user": { "settings": { - "currency": "CHF" + "currency": "CHF", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/novn-buy-and-sell.json b/test/import/ok/novn-buy-and-sell.json index 71ee9b7a9..6ae519d87 100644 --- a/test/import/ok/novn-buy-and-sell.json +++ b/test/import/ok/novn-buy-and-sell.json @@ -27,7 +27,8 @@ ], "user": { "settings": { - "currency": "CHF" + "currency": "CHF", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/penthouse-apartment.json b/test/import/ok/penthouse-apartment.json index 2bc7f0cf8..0c35521e6 100644 --- a/test/import/ok/penthouse-apartment.json +++ b/test/import/ok/penthouse-apartment.json @@ -47,7 +47,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/sample.json b/test/import/ok/sample.json index 21277129f..bc2798718 100644 --- a/test/import/ok/sample.json +++ b/test/import/ok/sample.json @@ -147,7 +147,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/vti-buy-long-history.json b/test/import/ok/vti-buy-long-history.json index c8cd25e60..88b38d2b1 100644 --- a/test/import/ok/vti-buy-long-history.json +++ b/test/import/ok/vti-buy-long-history.json @@ -40,7 +40,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } diff --git a/test/import/ok/without-accounts.json b/test/import/ok/without-accounts.json index 8a24f86fc..2283dd889 100644 --- a/test/import/ok/without-accounts.json +++ b/test/import/ok/without-accounts.json @@ -47,7 +47,8 @@ ], "user": { "settings": { - "currency": "USD" + "currency": "USD", + "performanceCalculationType": "ROAI" } } } From 5598b3780c008d20c19afba5869718be58a28bf7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 18:37:43 +0100 Subject: [PATCH 30/38] Feature/set up unit test for BTCEUR in base currency EUR (#5778) * Set up test --- ...ulator-btceur-in-base-currency-eur.spec.ts | 140 ++++++++++++++++++ .../exchange-rate-data.service.mock.ts | 10 ++ 2 files changed, 150 insertions(+) create mode 100644 apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts new file mode 100644 index 000000000..87893e647 --- /dev/null +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts @@ -0,0 +1,140 @@ +import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; +import { + activityDummyData, + loadExportFile, + symbolProfileDummyData, + userDummyData +} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; +import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock'; +import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; +import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; +import { parseDate } from '@ghostfolio/common/helper'; +import { ExportResponse } from '@ghostfolio/common/interfaces'; +import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; + +import { Big } from 'big.js'; +import { join } from 'node:path'; + +jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { + return { + CurrentRateService: jest.fn().mockImplementation(() => { + return CurrentRateServiceMock; + }) + }; +}); + +jest.mock( + '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service', + () => { + return { + ExchangeRateDataService: jest.fn().mockImplementation(() => { + return ExchangeRateDataServiceMock; + }) + }; + } +); + +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + +jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { + return { + RedisCacheService: jest.fn().mockImplementation(() => { + return RedisCacheServiceMock; + }) + }; +}); + +describe('PortfolioCalculator', () => { + let exportResponse: ExportResponse; + + let configurationService: ConfigurationService; + let currentRateService: CurrentRateService; + let exchangeRateDataService: ExchangeRateDataService; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; + let redisCacheService: RedisCacheService; + + beforeAll(() => { + exportResponse = loadExportFile( + join(__dirname, '../../../../../../../test/import/ok/btceur.json') + ); + }); + + beforeEach(() => { + configurationService = new ConfigurationService(); + + currentRateService = new CurrentRateService(null, null, null, null); + + exchangeRateDataService = new ExchangeRateDataService( + null, + null, + null, + null + ); + + portfolioSnapshotService = new PortfolioSnapshotService(null); + + redisCacheService = new RedisCacheService(null, null); + + portfolioCalculatorFactory = new PortfolioCalculatorFactory( + configurationService, + currentRateService, + exchangeRateDataService, + portfolioSnapshotService, + redisCacheService + ); + }); + + describe('get current positions', () => { + it.only('with BTCUSD buy (in EUR)', async () => { + jest.useFakeTimers().setSystemTime(parseDate('2022-01-14').getTime()); + + const activities: Activity[] = exportResponse.activities.map( + (activity) => ({ + ...activityDummyData, + ...activity, + date: parseDate(activity.date), + feeInAssetProfileCurrency: 4.46, + SymbolProfile: { + ...symbolProfileDummyData, + currency: 'USD', + dataSource: activity.dataSource, + name: 'Bitcoin', + symbol: activity.symbol + }, + unitPriceInAssetProfileCurrency: 44558.42 + }) + ); + + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ + activities, + calculationType: PerformanceCalculationType.ROAI, + currency: 'EUR', + userId: userDummyData.id + }); + + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); + + expect(portfolioSnapshot.positions[0].fee).toEqual(new Big(4.46)); + expect( + portfolioSnapshot.positions[0].feeInBaseCurrency.toNumber() + ).toBeCloseTo(3.94, 1); + }); + }); +}); diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts index 8f5d1c28a..076375523 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts @@ -17,11 +17,21 @@ export const ExchangeRateDataServiceMock = { '2023-07-10': 0.8854 } }); + } else if (targetCurrency === 'EUR') { + return Promise.resolve({ + EUREUR: { + '2021-12-12': 1 + }, + USDEUR: { + '2021-12-12': 0.8855 + } + }); } else if (targetCurrency === 'USD') { return Promise.resolve({ USDUSD: { '2018-01-01': 1, '2021-11-16': 1, + '2021-12-12': 1, '2023-07-10': 1 } }); From 96cad6ad7a54f0cbafaf83732daf7e6be080c66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20G=C3=BCnther?= Date: Sat, 1 Nov 2025 18:39:38 +0100 Subject: [PATCH 31/38] Feature/atomic data replacement during historical market data gathering (#5858) * Atomic data replacement during historical market data gathering * Update changelog --- CHANGELOG.md | 1 + .../api/src/services/interfaces/interfaces.ts | 1 + .../market-data/market-data.service.ts | 55 +++++++++++++++++++ .../data-gathering.processor.ts | 14 ++++- .../data-gathering/data-gathering.service.ts | 8 +-- 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 248aaa6ac..15e89924f 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 icon of the _View Holding_ menu item in the activities table +- Ensured atomic data replacement during historical market data gathering - Refreshed the cryptocurrencies list - Upgraded `ng-extract-i18n-merge` from version `3.0.0` to `3.1.0` diff --git a/apps/api/src/services/interfaces/interfaces.ts b/apps/api/src/services/interfaces/interfaces.ts index 7469754b5..492c2bd35 100644 --- a/apps/api/src/services/interfaces/interfaces.ts +++ b/apps/api/src/services/interfaces/interfaces.ts @@ -20,4 +20,5 @@ export interface DataProviderResponse { export interface DataGatheringItem extends AssetProfileIdentifier { date?: Date; + force?: boolean; } diff --git a/apps/api/src/services/market-data/market-data.service.ts b/apps/api/src/services/market-data/market-data.service.ts index 38ad61663..d318b9a70 100644 --- a/apps/api/src/services/market-data/market-data.service.ts +++ b/apps/api/src/services/market-data/market-data.service.ts @@ -132,6 +132,61 @@ export class MarketDataService { }); } + /** + * Atomically replace market data for a symbol within a date range. + * Deletes existing data in the range and inserts new data within a single + * transaction to prevent data loss if the operation fails. + */ + public async replaceForSymbol({ + data, + dataSource, + symbol + }: AssetProfileIdentifier & { data: Prisma.MarketDataUpdateInput[] }) { + await this.prismaService.$transaction(async (prisma) => { + if (data.length > 0) { + let minTime = Infinity; + let maxTime = -Infinity; + + for (const { date } of data) { + const time = (date as Date).getTime(); + + if (time < minTime) { + minTime = time; + } + + if (time > maxTime) { + maxTime = time; + } + } + + const minDate = new Date(minTime); + const maxDate = new Date(maxTime); + + await prisma.marketData.deleteMany({ + where: { + dataSource, + symbol, + date: { + gte: minDate, + lte: maxDate + } + } + }); + + await prisma.marketData.createMany({ + data: data.map(({ date, marketPrice, state }) => ({ + dataSource, + symbol, + date: date as Date, + marketPrice: marketPrice as number, + state: state as MarketDataState + })), + skipDuplicates: true + }); + } + }); + } + public async updateAssetProfileIdentifier( oldAssetProfileIdentifier: AssetProfileIdentifier, newAssetProfileIdentifier: AssetProfileIdentifier diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts index 1a172f3ea..1a4038652 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts @@ -100,7 +100,7 @@ export class DataGatheringProcessor { name: GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME }) public async gatherHistoricalMarketData(job: Job) { - const { dataSource, date, symbol } = job.data; + const { dataSource, date, force, symbol } = job.data; try { let currentDate = parseISO(date as unknown as string); @@ -109,7 +109,7 @@ export class DataGatheringProcessor { `Historical market data gathering has been started for ${symbol} (${dataSource}) at ${format( currentDate, DATE_FORMAT - )}`, + )}${force ? ' (forced update)' : ''}`, `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME})` ); @@ -157,7 +157,15 @@ export class DataGatheringProcessor { currentDate = addDays(currentDate, 1); } - await this.marketDataService.updateMany({ data }); + if (force) { + await this.marketDataService.replaceForSymbol({ + data, + dataSource, + symbol + }); + } else { + await this.marketDataService.updateMany({ data }); + } Logger.log( `Historical market data gathering has been completed for ${symbol} (${dataSource}) at ${format( diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts index 2d3ec45ad..c433f692f 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts @@ -2,7 +2,6 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data import { DataEnhancerInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-enhancer.interface'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { DataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; -import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; @@ -41,7 +40,6 @@ export class DataGatheringService { private readonly dataGatheringQueue: Queue, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly marketDataService: MarketDataService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly symbolProfileService: SymbolProfileService @@ -95,8 +93,6 @@ export class DataGatheringService { } public async gatherSymbol({ dataSource, date, symbol }: DataGatheringItem) { - await this.marketDataService.deleteMany({ dataSource, symbol }); - const dataGatheringItems = (await this.getSymbolsMax()) .filter((dataGatheringItem) => { return ( @@ -111,6 +107,7 @@ export class DataGatheringService { await this.gatherSymbols({ dataGatheringItems, + force: true, priority: DATA_GATHERING_QUEUE_PRIORITY_HIGH }); } @@ -274,9 +271,11 @@ export class DataGatheringService { public async gatherSymbols({ dataGatheringItems, + force = false, priority }: { dataGatheringItems: DataGatheringItem[]; + force?: boolean; priority: number; }) { await this.addJobsToQueue( @@ -285,6 +284,7 @@ export class DataGatheringService { data: { dataSource, date, + force, symbol }, name: GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME, From a4040c3c3c91eb01fa66bb53b9a95663f78f8ecc Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:28:22 +0100 Subject: [PATCH 32/38] Task/remove Internet Identity as social login provider (#5891) * Remove Internet Identity * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/auth/auth.controller.ts | 17 -- apps/api/src/app/auth/auth.service.ts | 37 --- ...ogin-with-access-token-dialog.component.ts | 18 +- .../login-with-access-token-dialog.html | 11 - .../pages/register/register-page.component.ts | 12 - .../src/app/pages/register/register-page.html | 14 -- .../app/services/internet-identity.service.ts | 56 ----- .../src/assets/icons/internet-computer.svg | 28 --- package-lock.json | 212 ++---------------- package.json | 5 - 11 files changed, 18 insertions(+), 393 deletions(-) delete mode 100644 apps/client/src/app/services/internet-identity.service.ts delete mode 100644 apps/client/src/assets/icons/internet-computer.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 15e89924f..2e4b9af16 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 - Improved the icon of the _View Holding_ menu item in the activities table - Ensured atomic data replacement during historical market data gathering +- Removed _Internet Identity_ as a social login provider - Refreshed the cryptocurrencies list - Upgraded `ng-extract-i18n-merge` from version `3.0.0` to `3.1.0` diff --git a/apps/api/src/app/auth/auth.controller.ts b/apps/api/src/app/auth/auth.controller.ts index 13d8e37f6..57fd04bc7 100644 --- a/apps/api/src/app/auth/auth.controller.ts +++ b/apps/api/src/app/auth/auth.controller.ts @@ -102,23 +102,6 @@ export class AuthController { } } - @Post('internet-identity') - public async internetIdentityLogin( - @Body() body: { principalId: string } - ): Promise { - try { - const authToken = await this.authService.validateInternetIdentityLogin( - body.principalId - ); - return { authToken }; - } catch { - throw new HttpException( - getReasonPhrase(StatusCodes.FORBIDDEN), - StatusCodes.FORBIDDEN - ); - } - } - @Get('webauthn/generate-registration-options') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async generateRegistrationOptions() { diff --git a/apps/api/src/app/auth/auth.service.ts b/apps/api/src/app/auth/auth.service.ts index ceff492a0..a6ee5d260 100644 --- a/apps/api/src/app/auth/auth.service.ts +++ b/apps/api/src/app/auth/auth.service.ts @@ -4,7 +4,6 @@ import { PropertyService } from '@ghostfolio/api/services/property/property.serv import { Injectable, InternalServerErrorException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { Provider } from '@prisma/client'; import { ValidateOAuthLoginParams } from './interfaces/interfaces'; @@ -44,42 +43,6 @@ export class AuthService { }); } - public async validateInternetIdentityLogin(principalId: string) { - try { - const provider: Provider = 'INTERNET_IDENTITY'; - - let [user] = await this.userService.users({ - where: { provider, thirdPartyId: principalId } - }); - - if (!user) { - const isUserSignupEnabled = - await this.propertyService.isUserSignupEnabled(); - - if (!isUserSignupEnabled || true) { - throw new Error('Sign up forbidden'); - } - - // Create new user if not found - user = await this.userService.createUser({ - data: { - provider, - thirdPartyId: principalId - } - }); - } - - return this.jwtService.sign({ - id: user.id - }); - } catch (error) { - throw new InternalServerErrorException( - 'validateInternetIdentityLogin', - error.message - ); - } - } - public async validateOAuthLogin({ provider, thirdPartyId diff --git a/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts b/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts index aaca03594..c0926150f 100644 --- a/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts +++ b/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts @@ -1,10 +1,8 @@ import { GfDialogHeaderComponent } from '@ghostfolio/client/components/dialog-header/dialog-header.component'; -import { InternetIdentityService } from '@ghostfolio/client/services/internet-identity.service'; import { KEY_STAY_SIGNED_IN, SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; @@ -21,7 +19,6 @@ import { } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { Router } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { eyeOffOutline, eyeOutline } from 'ionicons/icons'; @@ -55,10 +52,7 @@ export class GfLoginWithAccessTokenDialogComponent { public constructor( @Inject(MAT_DIALOG_DATA) public data: LoginWithAccessTokenDialogParams, public dialogRef: MatDialogRef, - private internetIdentityService: InternetIdentityService, - private router: Router, - private settingsStorageService: SettingsStorageService, - private tokenStorageService: TokenStorageService + private settingsStorageService: SettingsStorageService ) { addIcons({ eyeOffOutline, eyeOutline }); } @@ -81,14 +75,4 @@ export class GfLoginWithAccessTokenDialogComponent { }); } } - - public async onLoginWithInternetIdentity() { - try { - const { authToken } = await this.internetIdentityService.login(); - - this.tokenStorageService.saveToken(authToken); - this.dialogRef.close(); - this.router.navigate(['/']); - } catch {} - } } diff --git a/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html b/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html index b51802caf..15e68822a 100644 --- a/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html +++ b/apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -26,17 +26,6 @@ @if (data.hasPermissionToUseSocialLogin) {
or
- @if (hasPermissionForSocialLogin) {
or
- @if (false) { - - }
(); - - public constructor(private http: HttpClient) {} - - public async login(): Promise { - const authClient = await AuthClient.create({ - idleOptions: { - disableDefaultIdleCallback: true, - disableIdle: true - } - }); - - return new Promise((resolve, reject) => { - authClient.login({ - onError: async () => { - return reject(); - }, - onSuccess: () => { - const principalId = authClient.getIdentity().getPrincipal(); - - this.http - .post(`/api/v1/auth/internet-identity`, { - principalId: principalId.toText() - }) - .pipe( - catchError(() => { - reject(); - return EMPTY; - }), - takeUntil(this.unsubscribeSubject) - ) - .subscribe((response) => { - resolve(response); - }); - } - }); - }); - } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} diff --git a/apps/client/src/assets/icons/internet-computer.svg b/apps/client/src/assets/icons/internet-computer.svg deleted file mode 100644 index 6a1bf6c86..000000000 --- a/apps/client/src/assets/icons/internet-computer.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/package-lock.json b/package-lock.json index 914a783e0..3d2dfa25b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,11 +23,6 @@ "@angular/service-worker": "20.2.4", "@codewithdan/observable-store": "2.2.15", "@date-fns/utc": "2.1.0", - "@dfinity/agent": "0.15.7", - "@dfinity/auth-client": "0.15.7", - "@dfinity/candid": "0.15.7", - "@dfinity/identity": "0.15.7", - "@dfinity/principal": "0.15.7", "@internationalized/number": "3.6.3", "@ionic/angular": "8.7.3", "@keyv/redis": "4.4.0", @@ -4713,6 +4708,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -4725,6 +4721,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -4953,73 +4950,6 @@ "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@dfinity/agent": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-0.15.7.tgz", - "integrity": "sha512-w34yvlUTpPBG8nLOD0t/ao3k2xonOFq4QGvfJ1HiS/nIggdza/3xC3nLBszGrjVYWj1jqu8BLFvQXCAeWin75A==", - "license": "Apache-2.0", - "dependencies": { - "base64-arraybuffer": "^0.2.0", - "bignumber.js": "^9.0.0", - "borc": "^2.1.1", - "js-sha256": "0.9.0", - "simple-cbor": "^0.4.1", - "ts-node": "^10.8.2" - }, - "peerDependencies": { - "@dfinity/candid": "^0.15.7", - "@dfinity/principal": "^0.15.7" - } - }, - "node_modules/@dfinity/auth-client": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-0.15.7.tgz", - "integrity": "sha512-f6cRqXayCf+7+9gNcDnAZZwJrgBYKIzfxjxeRLlpsueQeo+E/BX2yVSANxzTkCNc4U3p+ttHI1RNtasLunYTcA==", - "license": "Apache-2.0", - "dependencies": { - "idb": "^7.0.2" - }, - "peerDependencies": { - "@dfinity/agent": "^0.15.7", - "@dfinity/identity": "^0.15.7", - "@dfinity/principal": "^0.15.7" - } - }, - "node_modules/@dfinity/candid": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-0.15.7.tgz", - "integrity": "sha512-lTcjK/xrSyT7wvUQ2pApG+yklQAwxaofQ04D1IWv0/8gKbY0eUbh8G2w6+CypJ15Hb1CH24ijUj8nWdeX/z3jg==", - "license": "Apache-2.0", - "dependencies": { - "ts-node": "^10.8.2" - } - }, - "node_modules/@dfinity/identity": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-0.15.7.tgz", - "integrity": "sha512-kBAkx9wq78jSQf6T5aayLyWm8YgtOZw8bW6+OuzX6tR3hkAEa85A9TcKA7BjkmMWSIskjEDVQub4fFfKWS2vOQ==", - "license": "Apache-2.0", - "dependencies": { - "borc": "^2.1.1", - "js-sha256": "^0.9.0", - "tweetnacl": "^1.0.1" - }, - "peerDependencies": { - "@dfinity/agent": "^0.15.7", - "@dfinity/principal": "^0.15.7", - "@peculiar/webcrypto": "^1.4.0" - } - }, - "node_modules/@dfinity/principal": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-0.15.7.tgz", - "integrity": "sha512-6/AkYzpGEH6Jw/0+B/EeeQn+5u2GDDvRLt1kQPhIG4txQYFnOy04H3VvyrymmfAj6/CXUgrOrux6OxgYSLYVJg==", - "license": "Apache-2.0", - "dependencies": { - "js-sha256": "^0.9.0", - "ts-node": "^10.8.2" - } - }, "node_modules/@discoveryjs/json-ext": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", @@ -11908,36 +11838,6 @@ "tslib": "^2.8.1" } }, - "node_modules/@peculiar/json-schema": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", - "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@peculiar/webcrypto": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", - "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2", - "webcrypto-core": "^1.8.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, "node_modules/@phenomnomnominal/tsquery": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz", @@ -13754,24 +13654,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, "license": "MIT" }, "node_modules/@tufjs/canonical-json": { @@ -15686,6 +15590,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -15732,6 +15637,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -16057,6 +15963,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, "license": "MIT" }, "node_modules/argparse": { @@ -16709,14 +16616,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-arraybuffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", - "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -17040,30 +16939,6 @@ "popper.js": "^1.16.1" } }, - "node_modules/borc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", - "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0", - "buffer": "^5.5.0", - "commander": "^2.15.0", - "ieee754": "^1.1.13", - "iso-url": "~0.4.7", - "json-text-sequence": "~0.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/borc/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -17160,6 +17035,7 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, "funding": [ { "type": "github", @@ -19325,6 +19201,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, "license": "MIT" }, "node_modules/cron": { @@ -20808,12 +20685,6 @@ "dev": true, "license": "MIT" }, - "node_modules/delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==", - "license": "BSD-2-Clause" - }, "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -20908,6 +20779,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -24840,12 +24712,6 @@ "postcss": "^8.1.0" } }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "license": "ISC" - }, "node_modules/identity-obj-proxy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", @@ -25837,15 +25703,6 @@ "dev": true, "license": "ISC" }, - "node_modules/iso-url": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", - "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", @@ -30098,12 +29955,6 @@ "license": "MIT", "peer": true }, - "node_modules/js-sha256": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", - "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==", - "license": "MIT" - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -30316,15 +30167,6 @@ "dev": true, "license": "ISC" }, - "node_modules/json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha512-L3mEegEWHRekSHjc7+sc8eJhba9Clq1PZ8kMkzf8OxElhXc8O4TS5MwcVlj9aEbm5dr81N90WHC5nAz3UO971w==", - "license": "MIT", - "dependencies": { - "delimit-stream": "0.1.0" - } - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -32083,6 +31925,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, "license": "ISC" }, "node_modules/make-fetch-happen": { @@ -38081,12 +37924,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/simple-cbor": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", - "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==", - "license": "ISC" - }, "node_modules/sirv": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", @@ -40042,6 +39879,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -40219,12 +40057,6 @@ "node": "*" } }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "license": "Unlicense" - }, "node_modules/twitter-api-v2": { "version": "1.23.0", "resolved": "https://registry.npmjs.org/twitter-api-v2/-/twitter-api-v2-1.23.0.tgz", @@ -40795,6 +40627,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -41110,20 +40943,6 @@ "license": "MIT", "optional": true }, - "node_modules/webcrypto-core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", - "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", - "license": "MIT", - "peer": true, - "dependencies": { - "@peculiar/asn1-schema": "^2.3.13", - "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.5", - "tslib": "^2.7.0" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -42424,6 +42243,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/package.json b/package.json index 43970a7f0..48ebb9215 100644 --- a/package.json +++ b/package.json @@ -69,11 +69,6 @@ "@angular/service-worker": "20.2.4", "@codewithdan/observable-store": "2.2.15", "@date-fns/utc": "2.1.0", - "@dfinity/agent": "0.15.7", - "@dfinity/auth-client": "0.15.7", - "@dfinity/candid": "0.15.7", - "@dfinity/identity": "0.15.7", - "@dfinity/principal": "0.15.7", "@internationalized/number": "3.6.3", "@ionic/angular": "8.7.3", "@keyv/redis": "4.4.0", From c8e6f9b38117b8256a1589a9e7ff71d294e8a66e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:28:51 +0100 Subject: [PATCH 33/38] Task/upgrade countries-list to version 3.2.0 (#5888) * Upgrade countries-list to version 3.2.0 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e4b9af16..f0a46c801 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 - Ensured atomic data replacement during historical market data gathering - Removed _Internet Identity_ as a social login provider - Refreshed the cryptocurrencies list +- Upgraded `countries-list` from version `3.1.1` to `3.2.0` - Upgraded `ng-extract-i18n-merge` from version `3.0.0` to `3.1.0` ## 2.213.0 - 2025-10-30 diff --git a/package-lock.json b/package-lock.json index 3d2dfa25b..0812c99b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "class-validator": "0.14.2", "color": "5.0.0", "countries-and-timezones": "3.8.0", - "countries-list": "3.1.1", + "countries-list": "3.2.0", "countup.js": "2.9.0", "date-fns": "4.1.0", "dotenv": "17.2.3", @@ -18523,9 +18523,9 @@ } }, "node_modules/countries-list": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.1.1.tgz", - "integrity": "sha512-nPklKJ5qtmY5MdBKw1NiBAoyx5Sa7p2yPpljZyQ7gyCN1m+eMFs9I6CT37Mxt8zvR5L3VzD3DJBE4WQzX3WF4A==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.2.0.tgz", + "integrity": "sha512-HYHAo2fwEsG3TmbsNdVmIQPHizRlqeYMTtLEAl0IANG/3jRYX7p3NR6VapDqKP0n60TmsRy1dyRjVN5JbywDbA==", "license": "MIT" }, "node_modules/countup.js": { diff --git a/package.json b/package.json index 48ebb9215..4f52177d2 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "class-validator": "0.14.2", "color": "5.0.0", "countries-and-timezones": "3.8.0", - "countries-list": "3.1.1", + "countries-list": "3.2.0", "countup.js": "2.9.0", "date-fns": "4.1.0", "dotenv": "17.2.3", From 6fd0a9a5c258807ee744a473bdab22d10d081da1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:38:41 +0100 Subject: [PATCH 34/38] Task/upgrade twitter-api-v2 to version 1.27.0 (#5892) * Upgrade twitter-api-v2 to version 1.27.0 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0a46c801..cf13e8ec3 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 - Refreshed the cryptocurrencies list - Upgraded `countries-list` from version `3.1.1` to `3.2.0` - Upgraded `ng-extract-i18n-merge` from version `3.0.0` to `3.1.0` +- Upgraded `twitter-api-v2` from version `1.23.0` to `1.27.0` ## 2.213.0 - 2025-10-30 diff --git a/package-lock.json b/package-lock.json index 0812c99b9..286dc628c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -88,7 +88,7 @@ "stripe": "18.5.0", "svgmap": "2.12.2", "tablemark": "4.1.0", - "twitter-api-v2": "1.23.0", + "twitter-api-v2": "1.27.0", "uuid": "11.1.0", "yahoo-finance2": "3.10.0", "zone.js": "0.15.1" @@ -40058,9 +40058,9 @@ } }, "node_modules/twitter-api-v2": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/twitter-api-v2/-/twitter-api-v2-1.23.0.tgz", - "integrity": "sha512-5i1agETVpTuY68Zuk9i2B3N9wHzc4JIWw0WKyG4CEaFv9mRKmU87roa+U1oYYXTChWb0HMcqfkwoBJHYmLbeDA==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/twitter-api-v2/-/twitter-api-v2-1.27.0.tgz", + "integrity": "sha512-hbIFwzg0NeOcFOdmJqtKMCXjLjc0INff/7NwhnZ2zpnw65oku8i+0eMxo5M0iTc1hs+inD/IpDw3S0Xh2c45QQ==", "license": "Apache-2.0" }, "node_modules/type-check": { diff --git a/package.json b/package.json index 4f52177d2..146b27c52 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "stripe": "18.5.0", "svgmap": "2.12.2", "tablemark": "4.1.0", - "twitter-api-v2": "1.23.0", + "twitter-api-v2": "1.27.0", "uuid": "11.1.0", "yahoo-finance2": "3.10.0", "zone.js": "0.15.1" From af2c46830627c8e6842f1b6ae1286c30270eaf31 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:40:06 +0100 Subject: [PATCH 35/38] Release 2.214.0 (#5893) --- 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 cf13e8ec3..fa39b0061 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 +## 2.214.0 - 2025-11-01 ### Changed diff --git a/package-lock.json b/package-lock.json index 286dc628c..6429912bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.213.0", + "version": "2.214.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.213.0", + "version": "2.214.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 146b27c52..7648cee02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.213.0", + "version": "2.214.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From a92f94e6970d84137cc093e7756c7456b39c2b79 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 2 Nov 2025 02:58:46 +0700 Subject: [PATCH 36/38] Feature/migrate client build executor to @nx/angular:browser-esbuild (#5883) * Migrate client build executor to @nx/angular:browser-esbuild * Update changelog --- CHANGELOG.md | 6 ++ apps/client/project.json | 56 +++++++++---------- .../portfolio-proportion-chart.component.ts | 3 +- .../treemap-chart/treemap-chart.component.ts | 3 +- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa39b0061..8ba1a6d7e 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 + +- Changed the build executor of the client from `@nx/angular:webpack-browser` to `@nx/angular:browser-esbuild` + ## 2.214.0 - 2025-11-01 ### Changed diff --git a/apps/client/project.json b/apps/client/project.json index adb63d5c1..0d3571cdf 100644 --- a/apps/client/project.json +++ b/apps/client/project.json @@ -61,30 +61,30 @@ }, "targets": { "build": { - "executor": "@nx/angular:webpack-browser", + "executor": "@nx/angular:browser-esbuild", "options": { - "deleteOutputPath": false, - "localize": true, - "outputPath": "dist/apps/client", "index": "apps/client/src/index.html", "main": "apps/client/src/main.ts", - "polyfills": "apps/client/src/polyfills.ts", + "outputPath": "dist/apps/client", "tsConfig": "apps/client/tsconfig.app.json", + "buildOptimizer": false, + "deleteOutputPath": false, + "extractLicenses": false, + "localize": true, + "namedChunks": true, + "ngswConfigPath": "apps/client/ngsw-config.json", + "optimization": false, + "polyfills": "apps/client/src/polyfills.ts", + "scripts": ["node_modules/marked/marked.min.js"], + "serviceWorker": true, + "sourceMap": true, "styles": [ "apps/client/src/assets/fonts/inter.css", "apps/client/src/styles/theme.scss", "apps/client/src/styles.scss", "node_modules/open-color/open-color.css" ], - "scripts": ["node_modules/marked/marked.min.js"], - "vendorChunk": true, - "extractLicenses": false, - "buildOptimizer": false, - "sourceMap": true, - "optimization": false, - "namedChunks": true, - "serviceWorker": true, - "ngswConfigPath": "apps/client/ngsw-config.json" + "vendorChunk": true }, "configurations": { "development-ca": { @@ -136,19 +136,6 @@ "localize": ["zh"] }, "production": { - "fileReplacements": [ - { - "replace": "apps/client/src/environments/environment.ts", - "with": "apps/client/src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -160,7 +147,20 @@ "maximumWarning": "6kb", "maximumError": "10kb" } - ] + ], + "buildOptimizer": true, + "extractLicenses": true, + "fileReplacements": [ + { + "replace": "apps/client/src/environments/environment.ts", + "with": "apps/client/src/environments/environment.prod.ts" + } + ], + "namedChunks": false, + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "vendorChunk": false } }, "outputs": ["{options.outputPath}"], diff --git a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts index 3f062a374..2d8a03ac0 100644 --- a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts +++ b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -31,6 +31,7 @@ import ChartDataLabels from 'chartjs-plugin-datalabels'; import { isUUID } from 'class-validator'; import Color from 'color'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import OpenColor from 'open-color'; import { translate } from '../i18n'; @@ -47,7 +48,7 @@ const { teal, violet, yellow -} = require('open-color'); +} = OpenColor; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts index 4e06d49cc..6ae958b83 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -33,10 +33,11 @@ import { isUUID } from 'class-validator'; import { differenceInDays, max } from 'date-fns'; import { orderBy } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import OpenColor from 'open-color'; import { GetColorParams } from './interfaces/interfaces'; -const { gray, green, red } = require('open-color'); +const { gray, green, red } = OpenColor; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, From 592baec9f3222502116fbdb1ef417546d2acc257 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Nov 2025 15:31:16 +0100 Subject: [PATCH 37/38] Bugfix/fix style of safe withdrawal rate selector (#5899) * Fix style of selector * Update changelog --- CHANGELOG.md | 4 ++ .../app/pages/portfolio/fire/fire-page.scss | 14 +++++ apps/client/src/styles/theme.scss | 61 +++++++++---------- apps/client/src/styles/variables.scss | 4 ++ 4 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 apps/client/src/styles/variables.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ba1a6d7e..5ecf2a57d 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 - Changed the build executor of the client from `@nx/angular:webpack-browser` to `@nx/angular:browser-esbuild` +### Fixed + +- Fixed the style of the safe withdrawal rate selector in the _FIRE_ section (experimental) + ## 2.214.0 - 2025-11-01 ### Changed diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.scss b/apps/client/src/app/pages/portfolio/fire/fire-page.scss index 2892885c9..3a0618ed6 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.scss +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.scss @@ -1,9 +1,21 @@ +@use '../../../../styles/variables.scss' as variables; + +@mixin select-arrow($color) { + background-image: url("data:image/svg+xml;utf8,"); +} + :host { display: block; .safe-withdrawal-rate-select { + @include select-arrow(variables.$dark-primary-text); + + appearance: none; background-color: transparent; + background-position: right 0 center; + background-repeat: no-repeat; color: rgb(var(--dark-primary-text)); + padding: 0 0.75rem 0 0.25rem; &:focus { box-shadow: none; @@ -14,6 +26,8 @@ :host-context(.theme-dark) { .safe-withdrawal-rate-select { + @include select-arrow(variables.$light-primary-text); + color: rgb(var(--light-primary-text)); } } diff --git a/apps/client/src/styles/theme.scss b/apps/client/src/styles/theme.scss index fe9fd44a5..8dd6d8e36 100644 --- a/apps/client/src/styles/theme.scss +++ b/apps/client/src/styles/theme.scss @@ -1,9 +1,6 @@ @use '@angular/material' as mat; -$dark-primary-text: rgba(black, 0.87); -$light-primary-text: white; - -$mat-css-dark-theme-selector: '.theme-dark'; +@use './variables.scss' as variables; $gf-primary: ( 50: var(--gf-theme-primary-50), @@ -21,20 +18,20 @@ $gf-primary: ( A400: var(--gf-theme-primary-A400), A700: var(--gf-theme-primary-A700), contrast: ( - 50: $dark-primary-text, - 100: $dark-primary-text, - 200: $dark-primary-text, - 300: $light-primary-text, - 400: $light-primary-text, - 500: $light-primary-text, - 600: $light-primary-text, - 700: $light-primary-text, - 800: $light-primary-text, - 900: $light-primary-text, - A100: $dark-primary-text, - A200: $light-primary-text, - A400: $light-primary-text, - A700: $light-primary-text + 50: variables.$dark-primary-text, + 100: variables.$dark-primary-text, + 200: variables.$dark-primary-text, + 300: variables.$light-primary-text, + 400: variables.$light-primary-text, + 500: variables.$light-primary-text, + 600: variables.$light-primary-text, + 700: variables.$light-primary-text, + 800: variables.$light-primary-text, + 900: variables.$light-primary-text, + A100: variables.$dark-primary-text, + A200: variables.$light-primary-text, + A400: variables.$light-primary-text, + A700: variables.$light-primary-text ) ); @@ -54,20 +51,20 @@ $gf-secondary: ( A400: var(--gf-theme-secondary-A400), A700: var(--gf-theme-secondary-A700), contrast: ( - 50: $dark-primary-text, - 100: $dark-primary-text, - 200: $dark-primary-text, - 300: $light-primary-text, - 400: $light-primary-text, - 500: $light-primary-text, - 600: $light-primary-text, - 700: $light-primary-text, - 800: $light-primary-text, - 900: $light-primary-text, - A100: $dark-primary-text, - A200: $light-primary-text, - A400: $light-primary-text, - A700: $light-primary-text + 50: variables.$dark-primary-text, + 100: variables.$dark-primary-text, + 200: variables.$dark-primary-text, + 300: variables.$light-primary-text, + 400: variables.$light-primary-text, + 500: variables.$light-primary-text, + 600: variables.$light-primary-text, + 700: variables.$light-primary-text, + 800: variables.$light-primary-text, + 900: variables.$light-primary-text, + A100: variables.$dark-primary-text, + A200: variables.$light-primary-text, + A400: variables.$light-primary-text, + A700: variables.$light-primary-text ) ); diff --git a/apps/client/src/styles/variables.scss b/apps/client/src/styles/variables.scss new file mode 100644 index 000000000..dcf26eecc --- /dev/null +++ b/apps/client/src/styles/variables.scss @@ -0,0 +1,4 @@ +$dark-primary-text: rgba(black, 0.87); +$light-primary-text: white; + +$mat-css-dark-theme-selector: '.theme-dark'; From a5f934460bc4a79d5eaeb9a912b917a4743e7b5f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Nov 2025 19:51:27 +0100 Subject: [PATCH 38/38] Task/introduce interface for get admin users response (#5903) * Introduce interface for get admin users response --- apps/api/src/app/admin/admin.controller.ts | 4 ++-- apps/api/src/app/admin/admin.service.ts | 6 +++--- .../app/components/admin-users/admin-users.component.ts | 8 ++++++-- .../user-detail-dialog/interfaces/interfaces.ts | 4 ++-- apps/client/src/app/services/admin.service.ts | 4 ++-- libs/common/src/lib/interfaces/index.ts | 4 ++-- .../admin-users-response.interface.ts} | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) rename libs/common/src/lib/interfaces/{admin-users.interface.ts => responses/admin-users-response.interface.ts} (88%) diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index d7c4c5d3d..2419b0a7d 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -17,7 +17,7 @@ import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { AdminData, AdminMarketData, - AdminUsers, + AdminUsersResponse, EnhancedSymbolProfile, ScraperConfiguration } from '@ghostfolio/common/interfaces'; @@ -315,7 +315,7 @@ export class AdminController { public async getUsers( @Query('skip') skip?: number, @Query('take') take?: number - ): Promise { + ): Promise { return this.adminService.getUsers({ skip: isNaN(skip) ? undefined : skip, take: isNaN(take) ? undefined : take diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 11f6f0599..683e72cb8 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -23,7 +23,7 @@ import { AdminMarketData, AdminMarketDataDetails, AdminMarketDataItem, - AdminUsers, + AdminUsersResponse, AssetProfileIdentifier, EnhancedSymbolProfile, Filter @@ -513,7 +513,7 @@ export class AdminService { }: { skip?: number; take?: number; - }): Promise { + }): Promise { const [count, users] = await Promise.all([ this.countUsersWithAnalytics(), this.getUsersWithAnalytics({ skip, take }) @@ -818,7 +818,7 @@ export class AdminService { }: { skip?: number; take?: number; - }): Promise { + }): Promise { let orderBy: Prisma.Enumerable = [ { createdAt: 'desc' } ]; diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index c0d058ad2..94b5839c6 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -5,7 +5,11 @@ import { getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper'; -import { AdminUsers, InfoItem, User } from '@ghostfolio/common/interfaces'; +import { + AdminUsersResponse, + InfoItem, + User +} from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -75,7 +79,7 @@ import { GfUserDetailDialogComponent } from '../user-detail-dialog/user-detail-d export class GfAdminUsersComponent implements OnDestroy, OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; - public dataSource = new MatTableDataSource(); + public dataSource = new MatTableDataSource(); public defaultDateFormat: string; public deviceType: string; public displayedColumns: string[] = []; diff --git a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts index 5f3f4b87a..d29bc01bc 100644 --- a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts @@ -1,8 +1,8 @@ -import { AdminUsers } from '@ghostfolio/common/interfaces'; +import { AdminUsersResponse } from '@ghostfolio/common/interfaces'; export interface UserDetailDialogParams { deviceType: string; hasPermissionForSubscription: boolean; locale: string; - userData: AdminUsers['users'][0]; + userData: AdminUsersResponse['users'][0]; } diff --git a/apps/client/src/app/services/admin.service.ts b/apps/client/src/app/services/admin.service.ts index a04ad8d56..2f3040ba3 100644 --- a/apps/client/src/app/services/admin.service.ts +++ b/apps/client/src/app/services/admin.service.ts @@ -12,7 +12,7 @@ import { AdminData, AdminJobs, AdminMarketData, - AdminUsers, + AdminUsersResponse, DataProviderGhostfolioStatusResponse, EnhancedSymbolProfile, Filter @@ -154,7 +154,7 @@ export class AdminService { params = params.append('skip', skip); params = params.append('take', take); - return this.http.get('/api/v1/admin/user', { params }); + return this.http.get('/api/v1/admin/user', { params }); } public gather7Days() { diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index eac5db68c..06ecf32e8 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -7,7 +7,6 @@ import type { AdminMarketData, AdminMarketDataItem } from './admin-market-data.interface'; -import type { AdminUsers } from './admin-users.interface'; import type { AssetClassSelectorOption } from './asset-class-selector-option.interface'; import type { AssetProfileIdentifier } from './asset-profile-identifier.interface'; import type { BenchmarkProperty } from './benchmark-property.interface'; @@ -39,6 +38,7 @@ import type { AccountBalancesResponse } from './responses/account-balances-respo import type { AccountsResponse } from './responses/accounts-response.interface'; import type { ActivitiesResponse } from './responses/activities-response.interface'; import type { ActivityResponse } from './responses/activity-response.interface'; +import type { AdminUsersResponse } from './responses/admin-users-response.interface'; import type { AiPromptResponse } from './responses/ai-prompt-response.interface'; import type { ApiKeyResponse } from './responses/api-key-response.interface'; import type { AssetResponse } from './responses/asset-response.interface'; @@ -92,7 +92,7 @@ export { AdminMarketData, AdminMarketDataDetails, AdminMarketDataItem, - AdminUsers, + AdminUsersResponse, AiPromptResponse, ApiKeyResponse, AssetClassSelectorOption, diff --git a/libs/common/src/lib/interfaces/admin-users.interface.ts b/libs/common/src/lib/interfaces/responses/admin-users-response.interface.ts similarity index 88% rename from libs/common/src/lib/interfaces/admin-users.interface.ts rename to libs/common/src/lib/interfaces/responses/admin-users-response.interface.ts index 79031425a..d9f58ee18 100644 --- a/libs/common/src/lib/interfaces/admin-users.interface.ts +++ b/libs/common/src/lib/interfaces/responses/admin-users-response.interface.ts @@ -1,6 +1,6 @@ import { Role } from '@prisma/client'; -export interface AdminUsers { +export interface AdminUsersResponse { count: number; users: { accountCount: number;