From d6d8ed9c11627164eb215b5c88243d5a51d9ed63 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:12:36 +0200 Subject: [PATCH 1/8] Task/upgrade fuse.js to version 7.5.0 (#7411) * Update fuse.js to version 7.5.0 * Update changelog --- CHANGELOG.md | 6 ++++++ package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c31cef39a..f9de4cb5a8 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 + +- Upgraded `fuse.js` from version `7.3.0` to `7.5.0` + ## 3.33.0 - 2026-07-25 ### Added diff --git a/package-lock.json b/package-lock.json index 4b94ed39fa..b70fcbbe52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,7 @@ "dotenv-expand": "12.0.3", "envalid": "8.2.0", "fast-redact": "3.5.0", - "fuse.js": "7.3.0", + "fuse.js": "7.5.0", "google-spreadsheet": "3.2.0", "helmet": "8.2.0", "http-status-codes": "2.3.0", @@ -21313,9 +21313,9 @@ } }, "node_modules/fuse.js": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.3.0.tgz", - "integrity": "sha512-plz8RVjfcDedTGfVngWH1jmJvBvAwi1v2jecfDerbEnMcmOYUEEwKFTHbNoCiYyzaK2Ws8lABkTCcRSqCY1q4w==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.5.0.tgz", + "integrity": "sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow==", "license": "Apache-2.0", "engines": { "node": ">=10" diff --git a/package.json b/package.json index 93e76af0bc..8013662854 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "dotenv-expand": "12.0.3", "envalid": "8.2.0", "fast-redact": "3.5.0", - "fuse.js": "7.3.0", + "fuse.js": "7.5.0", "google-spreadsheet": "3.2.0", "helmet": "8.2.0", "http-status-codes": "2.3.0", From b77f40a0ffcd8ea839d6e9bd0a10e59a1c032534 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:56:27 +0200 Subject: [PATCH 2/8] Bugfix/update account balance of activity without account (#7402) * Fix update account balance of activity without account * Update changelog --- CHANGELOG.md | 4 ++ apps/api/src/app/account/account.service.ts | 21 ++++++-- .../src/app/activities/activities.service.ts | 2 +- ...ate-or-update-activity-dialog.component.ts | 54 +++++++++---------- 4 files changed, 49 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9de4cb5a8..109beacbbf 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 - Upgraded `fuse.js` from version `7.3.0` to `7.5.0` +### Fixed + +- Resolved an exception in the `POST api/v1/activities` endpoint when creating an activity with the update account balance option but without an account + ## 3.33.0 - 2026-07-25 ### Added diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index f84f085a35..2098062340 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -37,11 +37,26 @@ export class AccountService { public async account({ id_userId }: Prisma.AccountWhereUniqueInput): Promise { - const [account] = await this.accounts({ - where: id_userId + const account = await this.prismaService.account.findUnique({ + include: { + balances: { + orderBy: { date: 'desc' }, + take: 1 + } + }, + where: { id_userId } }); - return account; + if (!account) { + return null; + } + + const { balances, ...accountData } = account; + + return { + ...accountData, + balance: balances[0]?.value ?? 0 + }; } public async accountWithActivities( diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index 459293abdd..fbe93d9a07 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -275,7 +275,7 @@ export class ActivitiesService { include: { SymbolProfile: true } }); - if (updateAccountBalance === true) { + if (accountId && updateAccountBalance === true) { let amount = new Big(data.unitPrice).mul(data.quantity); if (['BUY', 'FEE'].includes(data.type)) { diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index 79e1e8983d..632db1cd41 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -266,16 +266,9 @@ export class GfCreateOrUpdateActivityDialogComponent { this.activityForm.get('currency')?.setValue(currency); this.activityForm.get('currencyOfUnitPrice')?.setValue(currency); - - if (['FEE', 'INTEREST'].includes(type)) { - if (this.activityForm.get('accountId')?.value) { - this.activityForm.get('updateAccountBalance')?.enable(); - } else { - this.activityForm.get('updateAccountBalance')?.disable(); - this.activityForm.get('updateAccountBalance')?.setValue(false); - } - } } + + this.syncUpdateAccountBalanceControl(); }); this.activityForm @@ -299,12 +292,7 @@ export class GfCreateOrUpdateActivityDialogComponent { }); this.activityForm.get('date')?.valueChanges.subscribe(() => { - if (isToday(this.activityForm.get('date')?.value)) { - this.activityForm.get('updateAccountBalance')?.enable(); - } else { - this.activityForm.get('updateAccountBalance')?.disable(); - this.activityForm.get('updateAccountBalance')?.setValue(false); - } + this.syncUpdateAccountBalanceControl(); this.changeDetectorRef.markForCheck(); }); @@ -384,8 +372,6 @@ export class GfCreateOrUpdateActivityDialogComponent { .get('searchSymbol') ?.removeValidators(Validators.required); this.activityForm.get('searchSymbol')?.updateValueAndValidity(); - this.activityForm.get('updateAccountBalance')?.disable(); - this.activityForm.get('updateAccountBalance')?.setValue(false); } else if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { const currency = this.data.accounts.find(({ id }) => { @@ -421,16 +407,6 @@ export class GfCreateOrUpdateActivityDialogComponent { if (type === 'FEE') { this.activityForm.get('unitPrice')?.setValue(0); } - - if ( - ['FEE', 'INTEREST'].includes(type) && - this.activityForm.get('accountId')?.value - ) { - this.activityForm.get('updateAccountBalance')?.enable(); - } else { - this.activityForm.get('updateAccountBalance')?.disable(); - this.activityForm.get('updateAccountBalance')?.setValue(false); - } } else { this.activityForm .get('dataSource') @@ -442,9 +418,10 @@ export class GfCreateOrUpdateActivityDialogComponent { .get('searchSymbol') ?.setValidators(Validators.required); this.activityForm.get('searchSymbol')?.updateValueAndValidity(); - this.activityForm.get('updateAccountBalance')?.enable(); } + this.syncUpdateAccountBalanceControl(); + this.changeDetectorRef.markForCheck(); }); @@ -559,6 +536,27 @@ export class GfCreateOrUpdateActivityDialogComponent { } } + private syncUpdateAccountBalanceControl() { + const accountBalanceControl = this.activityForm.get('updateAccountBalance'); + const accountId = this.activityForm.get('accountId')?.value; + const dataSource = this.activityForm.get('dataSource')?.value; + const date = this.activityForm.get('date')?.value; + const type = this.activityForm.get('type')?.value; + + const isEligible = + !!accountId && + isToday(date) && + !['LIABILITY', 'VALUABLE'].includes(type) && + !(dataSource === 'MANUAL' && type === 'BUY'); + + if (isEligible) { + accountBalanceControl?.enable(); + } else { + accountBalanceControl?.disable(); + accountBalanceControl?.setValue(false); + } + } + private updateAssetProfile() { this.isLoading = true; this.changeDetectorRef.markForCheck(); From 10c01ec630294d79ae1dcfb78197bebe8ce5a394 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 25 Jul 2026 18:58:37 +0700 Subject: [PATCH 3/8] Task/improve type safety in access and account balance services (#7416) * fix(common): update Access interface and type definitions * fix(api): resolve type errors in access controller * feat(api): default to user currency in account balance service --- apps/api/src/app/access/access.controller.ts | 4 ++-- apps/api/src/app/account-balance/account-balance.service.ts | 2 +- libs/common/src/lib/interfaces/access.interface.ts | 2 +- libs/common/src/lib/types/access-with-grantee-user.type.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/api/src/app/access/access.controller.ts b/apps/api/src/app/access/access.controller.ts index d692f358df..3bad0e171e 100644 --- a/apps/api/src/app/access/access.controller.ts +++ b/apps/api/src/app/access/access.controller.ts @@ -78,7 +78,7 @@ export class AccessController { ): Promise { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Basic + this.request.user.subscription?.type === SubscriptionType.Basic ) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), @@ -134,7 +134,7 @@ export class AccessController { ): Promise { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Basic + this.request.user.subscription?.type === SubscriptionType.Basic ) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), diff --git a/apps/api/src/app/account-balance/account-balance.service.ts b/apps/api/src/app/account-balance/account-balance.service.ts index 656fc2f630..84932f4295 100644 --- a/apps/api/src/app/account-balance/account-balance.service.ts +++ b/apps/api/src/app/account-balance/account-balance.service.ts @@ -178,7 +178,7 @@ export class AccountBalanceService { accountId: balance.account.id, valueInBaseCurrency: this.exchangeRateDataService.toCurrency( balance.value, - balance.account.currency, + balance.account.currency ?? userCurrency, userCurrency ) }; diff --git a/libs/common/src/lib/interfaces/access.interface.ts b/libs/common/src/lib/interfaces/access.interface.ts index f3e74e7565..6b361d0b94 100644 --- a/libs/common/src/lib/interfaces/access.interface.ts +++ b/libs/common/src/lib/interfaces/access.interface.ts @@ -5,7 +5,7 @@ import { AccessPermission } from '@prisma/client'; import { AccessSettings } from './access-settings.interface'; export interface Access { - alias?: string; + alias: string | null; grantee?: string; id: string; permissions: AccessPermission[]; diff --git a/libs/common/src/lib/types/access-with-grantee-user.type.ts b/libs/common/src/lib/types/access-with-grantee-user.type.ts index 98551e0fdf..2fc2488eec 100644 --- a/libs/common/src/lib/types/access-with-grantee-user.type.ts +++ b/libs/common/src/lib/types/access-with-grantee-user.type.ts @@ -1,3 +1,3 @@ import { Access, User } from '@prisma/client'; -export type AccessWithGranteeUser = Access & { granteeUser?: User }; +export type AccessWithGranteeUser = Access & { granteeUser?: User | null }; From 7d338c2c6734f8b78b2482e49512712f44628397 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 25 Jul 2026 19:01:15 +0700 Subject: [PATCH 4/8] Task/improve type safety across API services and controllers (#7417) * fix(api): resolve subscription undefined type errors * fix(api): resolve session metadata null type errors * feat(api): add type declaration on promises * fix(api): resolve price undefined type errors * fix(api): resolve type errors in benchmark service --- .../app/endpoints/public/public.controller.ts | 6 +++--- apps/api/src/app/import/import.controller.ts | 4 ++-- .../src/app/portfolio/portfolio.controller.ts | 10 +++++----- .../app/subscription/subscription.service.ts | 2 +- .../src/services/benchmark/benchmark.service.ts | 17 ++++++++--------- .../yahoo-finance/yahoo-finance.service.ts | 10 +++++----- .../data-provider/data-provider.service.ts | 8 ++++---- 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts index 9bd2a78a84..67bed71ef3 100644 --- a/apps/api/src/app/endpoints/public/public.controller.ts +++ b/apps/api/src/app/endpoints/public/public.controller.ts @@ -65,7 +65,7 @@ export class PublicController { }); if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { - hasDetails = user.subscription.type === SubscriptionType.Premium; + hasDetails = user?.subscription?.type === SubscriptionType.Premium; } const { filters } = (access.settings ?? {}) as AccessSettings; @@ -98,7 +98,7 @@ export class PublicController { sortDirection: 'desc', take: 10, types: [ActivityType.BUY, ActivityType.SELL], - userCurrency: user.settings?.settings.baseCurrency ?? DEFAULT_CURRENCY, + userCurrency: user?.settings?.settings.baseCurrency ?? DEFAULT_CURRENCY, userId: user.id, withExcludedAccountsAndActivities: false }); @@ -167,7 +167,7 @@ export class PublicController { this.exchangeRateDataService.toCurrency( quantity * marketPrice, assetProfile.currency, - user.settings?.settings.baseCurrency ?? DEFAULT_CURRENCY + user?.settings?.settings.baseCurrency ?? DEFAULT_CURRENCY ) ); }) diff --git a/apps/api/src/app/import/import.controller.ts b/apps/api/src/app/import/import.controller.ts index c3e79a29f9..c2d53e3cb3 100644 --- a/apps/api/src/app/import/import.controller.ts +++ b/apps/api/src/app/import/import.controller.ts @@ -65,7 +65,7 @@ export class ImportController { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Premium + this.request.user.subscription?.type === SubscriptionType.Premium ) { maxActivitiesToImport = Number.MAX_SAFE_INTEGER; } @@ -109,7 +109,7 @@ export class ImportController { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Premium + this.request.user.subscription?.type === SubscriptionType.Premium ) { maxActivitiesToImport = Number.MAX_SAFE_INTEGER; } diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 13cc0eae7c..175532cadc 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -97,7 +97,7 @@ export class PortfolioController { if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { hasDetails = - this.request.user.subscription.type === SubscriptionType.Premium; + this.request.user.subscription?.type === SubscriptionType.Premium; } const filters = this.apiService.buildFiltersFromQueryParams({ @@ -383,7 +383,7 @@ export class PortfolioController { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Basic + this.request.user.subscription?.type === SubscriptionType.Basic ) { dividends = dividends.map((item) => { return nullifyValuesInObject(item, ['investment']); @@ -511,7 +511,7 @@ export class PortfolioController { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Basic + this.request.user.subscription?.type === SubscriptionType.Basic ) { investments = investments.map((item) => { return nullifyValuesInObject(item, ['investment']); @@ -623,7 +623,7 @@ export class PortfolioController { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Basic + this.request.user.subscription?.type === SubscriptionType.Basic ) { performanceInformation.chart = performanceInformation.chart.map( (item) => { @@ -651,7 +651,7 @@ export class PortfolioController { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - this.request.user.subscription.type === SubscriptionType.Basic + this.request.user.subscription?.type === SubscriptionType.Basic ) { for (const category of report.xRay.categories) { category.rules = null; diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index 83aee7c8e7..1dba93d472 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -149,7 +149,7 @@ export class SubscriptionService { } const subscriptionOffer: SubscriptionOffer = JSON.parse( - session.metadata.subscriptionOffer ?? '{}' + session.metadata?.subscriptionOffer ?? '{}' ); const durationExtension = subscriptionOffer?.durationExtension; diff --git a/apps/api/src/services/benchmark/benchmark.service.ts b/apps/api/src/services/benchmark/benchmark.service.ts index affb0da08f..17e729f9f4 100644 --- a/apps/api/src/services/benchmark/benchmark.service.ts +++ b/apps/api/src/services/benchmark/benchmark.service.ts @@ -18,7 +18,6 @@ import { BenchmarkProperty, BenchmarkResponse } from '@ghostfolio/common/interfaces'; -import { BenchmarkTrend } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { SymbolProfile } from '@prisma/client'; @@ -146,7 +145,7 @@ export class BenchmarkService { public async addBenchmark({ dataSource, symbol - }: AssetProfileIdentifier): Promise> { + }: AssetProfileIdentifier): Promise | undefined> { const assetProfile = await this.prismaService.symbolProfile.findFirst({ where: { dataSource, @@ -183,7 +182,7 @@ export class BenchmarkService { public async deleteBenchmark({ dataSource, symbol - }: AssetProfileIdentifier): Promise> { + }: AssetProfileIdentifier): Promise | null> { const assetProfile = await this.prismaService.symbolProfile.findFirst({ where: { dataSource, @@ -240,12 +239,12 @@ export class BenchmarkService { enableSharing }); - const promisesAllTimeHighs: Promise<{ date: Date; marketPrice: number }>[] = - []; - const promisesBenchmarkTrends: Promise<{ - trend50d: BenchmarkTrend; - trend200d: BenchmarkTrend; - }>[] = []; + const promisesAllTimeHighs: ReturnType< + typeof this.marketDataService.getMax + >[] = []; + const promisesBenchmarkTrends: ReturnType< + typeof this.getBenchmarkTrends + >[] = []; const quotes = await this.dataProviderService.getQuotes({ items: benchmarkAssetProfiles.map(({ dataSource, symbol }) => { diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts index 85ec6c020e..749f10c127 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts @@ -200,13 +200,13 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { response.assetClass = assetClass; response.assetSubClass = assetSubClass; - response.currency = assetProfile.price.currency; + response.currency = assetProfile.price?.currency; response.dataSource = this.getName(); response.name = this.formatName({ - longName: assetProfile.price.longName, - quoteType: assetProfile.price.quoteType, - shortName: assetProfile.price.shortName, - symbol: assetProfile.price.symbol + longName: assetProfile.price?.longName, + quoteType: assetProfile.price?.quoteType, + shortName: assetProfile.price?.shortName, + symbol: assetProfile.price?.symbol }); response.symbol = this.convertFromYahooFinanceSymbol( assetProfile.price.symbol diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 49f5f68f44..e8d5f5030b 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -99,7 +99,7 @@ export class DataProviderService implements OnModuleInit { return dataSource; }); - const promises = []; + const promises: Promise[] = []; for (const [dataSource, assetProfileIdentifiers] of Object.entries( itemsGroupedByDataSource @@ -248,7 +248,7 @@ export class DataProviderService implements OnModuleInit { if ( this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - user.subscription.type === SubscriptionType.Basic + user.subscription?.type === SubscriptionType.Basic ) { const dataProvider = this.getDataProvider(DataSource[dataSource]); @@ -660,7 +660,7 @@ export class DataProviderService implements OnModuleInit { } else if ( dataProvider.getDataProviderInfo().isPremium && this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - user?.subscription.type === SubscriptionType.Basic + user?.subscription?.type === SubscriptionType.Basic ) { // Skip symbols of Premium data providers for users without subscription return false; @@ -876,7 +876,7 @@ export class DataProviderService implements OnModuleInit { }) .map((lookupItem) => { if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { - if (user.subscription.type === SubscriptionType.Premium) { + if (user.subscription?.type === SubscriptionType.Premium) { lookupItem.dataProviderInfo.isPremium = false; } From 17b68c7f8385e91e95c7a2c94bb6a7b7eb52a667 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Jul 2026 14:08:14 +0200 Subject: [PATCH 5/8] Task/upgrade countup.js to version 2.10.1 (#7412) * Update countup.js to version 2.10.1 * 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 109beacbbf..2acb6b8c34 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 +- Upgraded `countup.js` from version `2.10.0` to `2.10.1` - Upgraded `fuse.js` from version `7.3.0` to `7.5.0` ### Fixed diff --git a/package-lock.json b/package-lock.json index b70fcbbe52..f8b696dfae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,7 +64,7 @@ "cookie-parser": "1.4.7", "countries-and-timezones": "3.9.0", "countries-list": "3.4.0", - "countup.js": "2.10.0", + "countup.js": "2.10.1", "date-fns": "4.4.0", "dotenv": "17.2.3", "dotenv-expand": "12.0.3", @@ -17068,9 +17068,9 @@ "license": "MIT" }, "node_modules/countup.js": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.10.0.tgz", - "integrity": "sha512-QQpZx7oYxsR+OeITlZe46fY/OQjV11oBqjY8wgIXzLU2jIz8GzOrbMhqKLysGY8bWI3T1ZNrYkwGzKb4JNgyzg==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.10.1.tgz", + "integrity": "sha512-UHW/BsPDgVZfN919D4iu2HPv+jJxZUuaR3EhT0ScFZaD446GiQtkMTgOnOyJXdA2AewdlyUk9UvERlTHTbVpcw==", "license": "MIT" }, "node_modules/create-require": { diff --git a/package.json b/package.json index 8013662854..f51973d50f 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "cookie-parser": "1.4.7", "countries-and-timezones": "3.9.0", "countries-list": "3.4.0", - "countup.js": "2.10.0", + "countup.js": "2.10.1", "date-fns": "4.4.0", "dotenv": "17.2.3", "dotenv-expand": "12.0.3", From 21e1c60e156b67fbfaae5e01bf3bd2fbc78ce2e8 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Jul 2026 14:31:35 +0200 Subject: [PATCH 6/8] Feature/include cash in portfolio performance (#7148) * Include cash in portfolio performance * Update changelog --- CHANGELOG.md | 1 + .../calculator/portfolio-calculator.ts | 90 ++++++++----------- .../roai/portfolio-calculator-btceur.spec.ts | 6 +- .../roai/portfolio-calculator-btcusd.spec.ts | 6 +- .../roai/portfolio-calculator-cash.spec.ts | 27 +++++- ...folio-calculator-novn-buy-and-sell.spec.ts | 6 +- .../calculator/roai/portfolio-calculator.ts | 7 +- .../src/app/portfolio/portfolio.service.ts | 11 +-- .../historical-data-item.interface.ts | 2 +- .../src/lib/models/portfolio-snapshot.ts | 4 + .../src/lib/models/timeline-position.ts | 2 - 11 files changed, 83 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2acb6b8c34..fac434a422 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 +- Included cash in the performance calculation of the portfolio - Upgraded `countup.js` from version `2.10.0` to `2.10.1` - Upgraded `fuse.js` from version `7.3.0` to `7.5.0` diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 606c223b48..8f603fc867 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -196,6 +196,7 @@ export abstract class PortfolioCalculator { hasErrors: false, historicalData: [], positions: [], + totalCashInBaseCurrency: new Big(0), totalFeesWithCurrencyEffect: new Big(0), totalInterestWithCurrencyEffect: new Big(0), totalInvestment: new Big(0), @@ -204,10 +205,12 @@ export abstract class PortfolioCalculator { }; } + const cashSymbols = new Set(); const currencies: { [symbol: string]: string } = {}; const dataGatheringItems: DataGatheringItem[] = []; let firstIndex = transactionPoints.length; let firstTransactionPoint: TransactionPoint = null; + let totalCashInBaseCurrency = new Big(0); let totalInterestWithCurrencyEffect = new Big(0); let totalLiabilitiesWithCurrencyEffect = new Big(0); @@ -316,7 +319,7 @@ export abstract class PortfolioCalculator { const accumulatedValuesByDate: { [date: string]: { investmentValueWithCurrencyEffect: Big; - totalAccountBalanceWithCurrencyEffect: Big; + totalCashValueWithCurrencyEffect: Big; totalCurrentValue: Big; totalCurrentValueWithCurrencyEffect: Big; totalInvestmentValue: Big; @@ -351,6 +354,8 @@ export abstract class PortfolioCalculator { ] ?? 1 ); + const valueInBaseCurrency = marketPriceInBaseCurrency.mul(item.quantity); + const { currentValues, currentValuesWithCurrencyEffect, @@ -391,25 +396,19 @@ export abstract class PortfolioCalculator { hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors; - const includeInTotalAssetValue = - item.assetSubClass !== AssetSubClass.CASH; - - if (includeInTotalAssetValue) { - valuesBySymbol[item.symbol] = { - currentValues, - currentValuesWithCurrencyEffect, - investmentValuesAccumulated, - investmentValuesAccumulatedWithCurrencyEffect, - investmentValuesWithCurrencyEffect, - netPerformanceValues, - netPerformanceValuesWithCurrencyEffect, - timeWeightedInvestmentValues, - timeWeightedInvestmentValuesWithCurrencyEffect - }; - } + valuesBySymbol[item.symbol] = { + currentValues, + currentValuesWithCurrencyEffect, + investmentValuesAccumulated, + investmentValuesAccumulatedWithCurrencyEffect, + investmentValuesWithCurrencyEffect, + netPerformanceValues, + netPerformanceValuesWithCurrencyEffect, + timeWeightedInvestmentValues, + timeWeightedInvestmentValuesWithCurrencyEffect + }; positions.push({ - includeInTotalAssetValue, timeWeightedInvestment, timeWeightedInvestmentWithCurrencyEffect, activitiesCount: item.activitiesCount, @@ -450,11 +449,16 @@ export abstract class PortfolioCalculator { quantity: item.quantity, symbol: item.symbol, tags: item.tags, - valueInBaseCurrency: new Big(marketPriceInBaseCurrency).mul( - item.quantity - ) + valueInBaseCurrency }); + if (item.assetSubClass === AssetSubClass.CASH) { + cashSymbols.add(item.symbol); + + totalCashInBaseCurrency = + totalCashInBaseCurrency.plus(valueInBaseCurrency); + } + totalInterestWithCurrencyEffect = totalInterestWithCurrencyEffect.plus( totalInterestInBaseCurrency ); @@ -474,28 +478,7 @@ export abstract class PortfolioCalculator { } } - const accountBalanceItemsMap = this.accountBalanceItems.reduce( - (map, { date, value }) => { - map[date] = new Big(value); - - return map; - }, - {} as { [date: string]: Big } - ); - - const accountBalanceMap: { [date: string]: Big } = {}; - - let lastKnownBalance = new Big(0); - for (const dateString of chartDates) { - if (accountBalanceItemsMap[dateString] !== undefined) { - // If there's an exact balance for this date, update lastKnownBalance - lastKnownBalance = accountBalanceItemsMap[dateString]; - } - - // Add the most recent balance to the accountBalanceMap - accountBalanceMap[dateString] = lastKnownBalance; - for (const symbol of Object.keys(valuesBySymbol)) { const symbolValues = valuesBySymbol[symbol]; @@ -538,7 +521,14 @@ export abstract class PortfolioCalculator { accumulatedValuesByDate[dateString] ?.investmentValueWithCurrencyEffect ?? new Big(0) ).add(investmentValueWithCurrencyEffect), - totalAccountBalanceWithCurrencyEffect: accountBalanceMap[dateString], + totalCashValueWithCurrencyEffect: ( + accumulatedValuesByDate[dateString] + ?.totalCashValueWithCurrencyEffect ?? new Big(0) + ).add( + cashSymbols.has(symbol) + ? currentValueWithCurrencyEffect + : new Big(0) + ), totalCurrentValue: ( accumulatedValuesByDate[dateString]?.totalCurrentValue ?? new Big(0) ).add(currentValue), @@ -579,7 +569,7 @@ export abstract class PortfolioCalculator { ).map(([date, values]) => { const { investmentValueWithCurrencyEffect, - totalAccountBalanceWithCurrencyEffect, + totalCashValueWithCurrencyEffect, totalCurrentValue, totalCurrentValueWithCurrencyEffect, totalInvestmentValue, @@ -612,10 +602,8 @@ export abstract class PortfolioCalculator { netPerformance: totalNetPerformanceValue.toNumber(), netPerformanceWithCurrencyEffect: totalNetPerformanceValueWithCurrencyEffect.toNumber(), - netWorth: totalCurrentValueWithCurrencyEffect - .plus(totalAccountBalanceWithCurrencyEffect) - .toNumber(), - totalAccountBalance: totalAccountBalanceWithCurrencyEffect.toNumber(), + netWorth: totalCurrentValueWithCurrencyEffect.toNumber(), + totalCashInBaseCurrency: totalCashValueWithCurrencyEffect.toNumber(), totalInvestment: totalInvestmentValue.toNumber(), totalInvestmentValueWithCurrencyEffect: totalInvestmentValueWithCurrencyEffect.toNumber(), @@ -639,6 +627,7 @@ export abstract class PortfolioCalculator { ...overall, errors, historicalData, + totalCashInBaseCurrency, totalInterestWithCurrencyEffect, totalLiabilitiesWithCurrencyEffect, hasErrors: hasAnySymbolMetricsErrors || overall.hasErrors, @@ -776,11 +765,6 @@ export abstract class PortfolioCalculator { ? 0 : netPerformanceWithCurrencyEffectSinceStartDate / timeWeightedInvestmentValue - // TODO: Add net worth - // netWorth: totalCurrentValueWithCurrencyEffect - // .plus(totalAccountBalanceWithCurrencyEffect) - // .toNumber() - // netWorth: 0 }); } } diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts index bc80e89964..4f5da58b85 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts @@ -145,7 +145,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, netWorth: 0, - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0, value: 0, @@ -163,7 +163,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0.12422837255001412, // 5535.42 ÷ 44558.42 = 0.12422837255001412 netPerformanceWithCurrencyEffect: 5535.42, netWorth: 50098.3, // 1 * 50098.3 = 50098.3 - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 44558.42, totalInvestmentValueWithCurrencyEffect: 44558.42, value: 50098.3, // 1 * 50098.3 = 50098.3 @@ -182,7 +182,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: -0.032837340282712, netPerformanceWithCurrencyEffect: -1463.18, netWorth: 43099.7, - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 44558.42, totalInvestmentValueWithCurrencyEffect: 44558.42, value: 43099.7, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts index 18b0e6d647..eb5571feb1 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts @@ -145,7 +145,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, netWorth: 0, - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0, value: 0, @@ -163,7 +163,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0.12422837255001412, // 5535.42 ÷ 44558.42 = 0.12422837255001412 netPerformanceWithCurrencyEffect: 5535.42, // 1 * (50098.3 - 44558.42) - 4.46 = 5535.42 netWorth: 50098.3, // 1 * 50098.3 = 50098.3 - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 44558.42, totalInvestmentValueWithCurrencyEffect: 44558.42, value: 50098.3, // 1 * 50098.3 = 50098.3 @@ -182,7 +182,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: -0.032837340282712, netPerformanceWithCurrencyEffect: -1463.18, netWorth: 43099.7, - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 44558.42, totalInvestmentValueWithCurrencyEffect: 44558.42, value: 43099.7, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index 31e451051e..551189fccc 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -248,7 +248,6 @@ describe('PortfolioCalculator', () => { '0.08211603004634809014' ), grossPerformanceWithCurrencyEffect: new Big(70), - includeInTotalAssetValue: false, investment: new Big(1820), investmentWithCurrencyEffect: new Big(1750), marketPrice: 1, @@ -283,11 +282,37 @@ describe('PortfolioCalculator', () => { }); expect(portfolioSnapshot).toMatchObject({ + currentValueInBaseCurrency: new Big(1820), hasErrors: false, + totalCashInBaseCurrency: new Big(1820), totalFeesWithCurrencyEffect: new Big(0), totalInterestWithCurrencyEffect: new Big(0), + totalInvestment: new Big(1820), totalLiabilitiesWithCurrencyEffect: new Big(0) }); + + /** + * Value with currency effect: 2000 USD * 0.91 = 1820 CHF + * Net worth: 1820 CHF (the cash is included in the value and therefore + * not added on top of it again) + * Cash in base currency: 2000 USD * 0.91 = 1820 CHF (the whole portfolio + * consists of cash, hence it matches the value) + * Net performance with currency effect: 70 CHF / 852.45 CHF ≈ 8.21 % + */ + expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ + date: '2025-01-01', + investmentValueWithCurrencyEffect: 0, + netPerformance: 0, + netPerformanceInPercentage: 0, + netPerformanceInPercentageWithCurrencyEffect: 0.08211603004634808, + netPerformanceWithCurrencyEffect: 70, + netWorth: 1820, + totalCashInBaseCurrency: 1820, + totalInvestment: 1820, + totalInvestmentValueWithCurrencyEffect: 1750, + value: 1820, + valueWithCurrencyEffect: 1820 + }); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index f86b23d9ad..10cc2da01f 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -142,7 +142,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, netWorth: 0, - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0, value: 0, @@ -161,7 +161,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0.158311345646438, // 24 ÷ 151.6 = 0.158311345646438 netPerformanceWithCurrencyEffect: 24, netWorth: 175.6, // 2 * 87.8 = 175.6 - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 151.6, totalInvestmentValueWithCurrencyEffect: 151.6, value: 175.6, // 2 * 87.8 = 175.6 @@ -180,7 +180,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744, netPerformanceWithCurrencyEffect: 19.86, netWorth: 0, - totalAccountBalance: 0, + totalCashInBaseCurrency: 0, totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0, value: 0, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index 747fca7a5a..18a8f7cd85 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -40,11 +40,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { let totalTimeWeightedInvestment = new Big(0); let totalTimeWeightedInvestmentWithCurrencyEffect = new Big(0); - for (const currentPosition of positions.filter( - ({ includeInTotalAssetValue }) => { - return includeInTotalAssetValue; - } - )) { + for (const currentPosition of positions) { if (currentPosition.feeInBaseCurrency) { totalFeesWithCurrencyEffect = totalFeesWithCurrencyEffect.plus( currentPosition.feeInBaseCurrency @@ -117,6 +113,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { createdAt: new Date(), errors: [], historicalData: [], + totalCashInBaseCurrency: new Big(0), totalLiabilitiesWithCurrencyEffect: new Big(0) }; } diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index b3e86e0502..24112299d0 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -541,12 +541,6 @@ export class PortfolioService { let filteredValueInBaseCurrency = currentValueInBaseCurrency; - if (!this.activitiesService.areCashActivitiesExcludedByFilters(filters)) { - filteredValueInBaseCurrency = filteredValueInBaseCurrency.plus( - cashDetails.balanceInBaseCurrency - ); - } - const assetProfileIdentifiers = positions.map(({ dataSource, symbol }) => { return { dataSource, @@ -1906,6 +1900,7 @@ export class PortfolioService { const { currentValueInBaseCurrency, + totalCashInBaseCurrency, totalInvestment, totalInvestmentWithCurrencyEffect } = await portfolioCalculator.getSnapshot(); @@ -1982,8 +1977,7 @@ export class PortfolioService { .plus(totalOfExcludedActivities) .toNumber(); - const netWorth = new Big(balanceInBaseCurrency) - .plus(currentValueInBaseCurrency) + const netWorth = new Big(currentValueInBaseCurrency) .plus(excludedAccountsAndActivities) .minus(liabilities) .toNumber(); @@ -2035,6 +2029,7 @@ export class PortfolioService { fireWealth: { today: { valueInBaseCurrency: new Big(currentValueInBaseCurrency) + .minus(totalCashInBaseCurrency ?? 0) .minus(emergencyFundHoldingsValueInBaseCurrency) .toNumber() } diff --git a/libs/common/src/lib/interfaces/historical-data-item.interface.ts b/libs/common/src/lib/interfaces/historical-data-item.interface.ts index 0b45cf0b77..adb5b7e655 100644 --- a/libs/common/src/lib/interfaces/historical-data-item.interface.ts +++ b/libs/common/src/lib/interfaces/historical-data-item.interface.ts @@ -11,7 +11,7 @@ export interface HistoricalDataItem { netWorth?: number; netWorthInPercentage?: number; quantity?: number; - totalAccountBalance?: number; + totalCashInBaseCurrency?: number; totalInvestment?: number; totalInvestmentValueWithCurrencyEffect?: number; value?: number; diff --git a/libs/common/src/lib/models/portfolio-snapshot.ts b/libs/common/src/lib/models/portfolio-snapshot.ts index 6b13ca0481..17e4bf97d8 100644 --- a/libs/common/src/lib/models/portfolio-snapshot.ts +++ b/libs/common/src/lib/models/portfolio-snapshot.ts @@ -26,6 +26,10 @@ export class PortfolioSnapshot { @Type(() => TimelinePosition) positions: TimelinePosition[]; + @Transform(transformToBig, { toClassOnly: true }) + @Type(() => Big) + totalCashInBaseCurrency: Big; + @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) totalFeesWithCurrencyEffect: Big; diff --git a/libs/common/src/lib/models/timeline-position.ts b/libs/common/src/lib/models/timeline-position.ts index 13f9001d59..b16db49881 100644 --- a/libs/common/src/lib/models/timeline-position.ts +++ b/libs/common/src/lib/models/timeline-position.ts @@ -51,8 +51,6 @@ export class TimelinePosition { @Type(() => Big) grossPerformanceWithCurrencyEffect: Big; - includeInTotalAssetValue?: boolean; - @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) investment: Big; From c90142fae92cc5bf1615e3b85383897c88797ffd Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Jul 2026 14:52:02 +0200 Subject: [PATCH 7/8] Bugfix/links to open create activity dialog (#7418) * Fix links to open create activity dialog * Update changelog --- CHANGELOG.md | 2 ++ .../app/components/home-overview/home-overview.component.ts | 2 ++ .../src/app/components/home-overview/home-overview.html | 2 +- .../no-transactions-info/no-transactions-info.component.html | 3 +-- .../no-transactions-info/no-transactions-info.component.ts | 4 ++-- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fac434a422..1da7d38ec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed the _Add activity_ link of the onboarding on the overview tab of the home page to open the create activity dialog +- Fixed the link of the no transactions info component to open the create activity dialog - Resolved an exception in the `POST api/v1/activities` endpoint when creating an activity with the update account balance option but without an account ## 3.33.0 - 2026-07-25 diff --git a/apps/client/src/app/components/home-overview/home-overview.component.ts b/apps/client/src/app/components/home-overview/home-overview.component.ts index ad35565369..24d582ff82 100644 --- a/apps/client/src/app/components/home-overview/home-overview.component.ts +++ b/apps/client/src/app/components/home-overview/home-overview.component.ts @@ -58,6 +58,8 @@ export class GfHomeOverviewComponent implements OnInit { protected readonly routerLinkPortfolio = internalRoutes.portfolio.routerLink; protected readonly routerLinkPortfolioActivities = internalRoutes.portfolio.subRoutes.activities.routerLink; + protected readonly routerLinkPortfolioActivitiesCreate = + internalRoutes.portfolio.subRoutes.activities.subRoutes.create.routerLink; protected readonly deviceType = computed( () => this.deviceDetectorService.deviceInfo().deviceType diff --git a/apps/client/src/app/components/home-overview/home-overview.html b/apps/client/src/app/components/home-overview/home-overview.html index 0ca4912b92..90a628a170 100644 --- a/apps/client/src/app/components/home-overview/home-overview.html +++ b/apps/client/src/app/components/home-overview/home-overview.html @@ -52,7 +52,7 @@ Add activity diff --git a/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html b/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html index f1a2a3f90e..3c7f9fd107 100644 --- a/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html +++ b/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html @@ -6,8 +6,7 @@ class="align-items-center justify-content-center" color="primary" mat-button - [queryParams]="{ createDialog: true }" - [routerLink]="routerLinkPortfolioActivities" + [routerLink]="routerLinkPortfolioActivitiesCreate" > Time to add your first activity. diff --git a/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.ts b/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.ts index 8691dc998d..d23aa43689 100644 --- a/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.ts +++ b/libs/ui/src/lib/no-transactions-info/no-transactions-info.component.ts @@ -23,6 +23,6 @@ import { GfLogoComponent } from '../logo'; export class GfNoTransactionsInfoComponent { @HostBinding('class.has-border') @Input() hasBorder = true; - public routerLinkPortfolioActivities = - internalRoutes.portfolio.subRoutes.activities.routerLink; + public routerLinkPortfolioActivitiesCreate = + internalRoutes.portfolio.subRoutes.activities.subRoutes.create.routerLink; } From 50dfce902ee4661b2187e45ab2c28243e036a753 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 25 Jul 2026 15:03:59 +0200 Subject: [PATCH 8/8] Task/upgrade dotenv dependencies (20260725) (#7419) * Update dotenv and dotenv-expand * Update changelog --- CHANGELOG.md | 2 ++ package-lock.json | 86 ++++++++++++++++++++++++++++------------------- package.json | 4 +-- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da7d38ec3..0ddf39b89a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Included cash in the performance calculation of the portfolio - Upgraded `countup.js` from version `2.10.0` to `2.10.1` +- Upgraded `dotenv` from version `17.2.3` to `17.4.2` +- Upgraded `dotenv-expand` from version `12.0.3` to `13.0.0` - Upgraded `fuse.js` from version `7.3.0` to `7.5.0` ### Fixed diff --git a/package-lock.json b/package-lock.json index f8b696dfae..46f5194826 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,8 +66,8 @@ "countries-list": "3.4.0", "countup.js": "2.10.1", "date-fns": "4.4.0", - "dotenv": "17.2.3", - "dotenv-expand": "12.0.3", + "dotenv": "17.4.2", + "dotenv-expand": "13.0.0", "envalid": "8.2.0", "fast-redact": "3.5.0", "fuse.js": "7.5.0", @@ -7090,6 +7090,33 @@ "url": "https://dotenvx.com" } }, + "node_modules/@nestjs/config/node_modules/dotenv-expand": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", + "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@nestjs/config/node_modules/dotenv-expand/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/@nestjs/core": { "version": "11.1.27", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.27.tgz", @@ -15770,19 +15797,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/c12/node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "devOptional": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/c12/node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -19169,9 +19183,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -19181,12 +19195,12 @@ } }, "node_modules/dotenv-expand": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", - "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz", + "integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==", "license": "BSD-2-Clause", "dependencies": { - "dotenv": "^16.4.5" + "dotenv": "^17.4.2" }, "engines": { "node": ">=12" @@ -19195,18 +19209,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/dotenv-expand/node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -27154,6 +27156,22 @@ "url": "https://dotenvx.com" } }, + "node_modules/nx/node_modules/dotenv-expand": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", + "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/nx/node_modules/ejs": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.1.tgz", diff --git a/package.json b/package.json index f51973d50f..b4348197b3 100644 --- a/package.json +++ b/package.json @@ -110,8 +110,8 @@ "countries-list": "3.4.0", "countup.js": "2.10.1", "date-fns": "4.4.0", - "dotenv": "17.2.3", - "dotenv-expand": "12.0.3", + "dotenv": "17.4.2", + "dotenv-expand": "13.0.0", "envalid": "8.2.0", "fast-redact": "3.5.0", "fuse.js": "7.5.0",