diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e7e74731..1830b7962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Removed the `transactionCount` in the portfolio calculator and service + ### Fixed - Fixed the accounts of the assistant for the impersonation mode - Fixed the tags of the assistant for the impersonation mode +## 2.236.0 - 2026-02-05 + +### Changed + +- Removed the deprecated `transactionCount` in the endpoint `GET api/v1/admin` +- Upgraded `stripe` from version `20.1.0` to `20.3.0` + +### Fixed + +- Fixed an exception when fetching the top holdings for ETF and mutual fund assets from _Yahoo Finance_ + +## 2.235.0 - 2026-02-03 + +### Added + +- Added the ability to fetch top holdings for ETF and mutual fund assets from _Yahoo Finance_ +- Added support for the impersonation mode in the endpoint `GET api/v1/account/:id/balances` +- Added an action menu to the user detail dialog in the users section of the admin control panel + +### Changed + +- Optimized the value redaction interceptor for the impersonation mode by introducing `fast-redact` +- Refactored `showTransactions` in favor of `showActivitiesCount` in the accounts table component +- Refactored `transactionCount` in favor of `activitiesCount` in the accounts table component +- Deprecated `transactionCount` in favor of `activitiesCount` in the endpoint `GET api/v1/admin` +- Removed the deprecated `firstBuyDate` in the portfolio calculator +- Upgraded `yahoo-finance2` from version `3.11.2` to `3.13.0` + +## 2.234.0 - 2026-01-30 + +### Changed + +- Improved the usability of the create asset profile dialog in the market data section of the admin control panel +- Improved the language localization for Chinese (`zh`) +- Improved the language localization for German (`de`) +- Improved the language localization for Spanish (`es`) +- Upgraded `angular` from version `21.0.6` to `21.1.1` +- Upgraded `lodash` from version `4.17.21` to `4.17.23` +- Upgraded `Nx` from version `22.3.3` to `22.4.1` +- Upgraded `prettier` from version `3.8.0` to `3.8.1` + ## 2.233.0 - 2026-01-23 ### Changed diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 542b199fd..052720176 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -132,12 +132,16 @@ export class AccountController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) public async getAccountBalancesById( + @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Param('id') id: string ): Promise { + const impersonationUserId = + await this.impersonationService.validateImpersonationId(impersonationId); + return this.accountBalanceService.getAccountBalances({ filters: [{ id, type: 'ACCOUNT' }], userCurrency: this.request.user.settings.settings.baseCurrency, - userId: this.request.user.id + userId: impersonationUserId || this.request.user.id }); } diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 398a89bb9..e1b01a6ed 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -150,15 +150,15 @@ export class AccountService { }); return accounts.map((account) => { - let transactionCount = 0; + let activitiesCount = 0; for (const { isDraft } of account.activities) { if (!isDraft) { - transactionCount += 1; + activitiesCount += 1; } } - const result = { ...account, transactionCount }; + const result = { ...account, activitiesCount }; delete result.activities; diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 705085a48..2cc8bbfb8 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -138,11 +138,11 @@ export class AdminService { public async get(): Promise { const dataSources = Object.values(DataSource); - const [enabledDataSources, settings, transactionCount, userCount] = + const [activitiesCount, enabledDataSources, settings, userCount] = await Promise.all([ + this.prismaService.order.count(), this.dataProviderService.getDataSources(), this.propertyService.get(), - this.prismaService.order.count(), this.countUsersWithAnalytics() ]); @@ -182,9 +182,9 @@ export class AdminService { ).filter(Boolean); return { + activitiesCount, dataProviders, settings, - transactionCount, userCount, version: environment.version }; diff --git a/apps/api/src/app/endpoints/market-data/market-data.controller.ts b/apps/api/src/app/endpoints/market-data/market-data.controller.ts index 987d34918..0dae82d2c 100644 --- a/apps/api/src/app/endpoints/market-data/market-data.controller.ts +++ b/apps/api/src/app/endpoints/market-data/market-data.controller.ts @@ -2,6 +2,8 @@ import { AdminService } from '@ghostfolio/api/app/admin/admin.service'; import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; +import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { @@ -28,7 +30,8 @@ import { Param, Post, Query, - UseGuards + UseGuards, + UseInterceptors } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; @@ -86,6 +89,8 @@ export class MarketDataController { @Get(':dataSource/:symbol') @UseGuards(AuthGuard('jwt')) + @UseInterceptors(TransformDataSourceInRequestInterceptor) + @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getMarketDataBySymbol( @Param('dataSource') dataSource: DataSource, @Param('symbol') symbol: string diff --git a/apps/api/src/app/endpoints/market-data/market-data.module.ts b/apps/api/src/app/endpoints/market-data/market-data.module.ts index a8b355de3..d5d64673d 100644 --- a/apps/api/src/app/endpoints/market-data/market-data.module.ts +++ b/apps/api/src/app/endpoints/market-data/market-data.module.ts @@ -1,5 +1,7 @@ import { AdminModule } from '@ghostfolio/api/app/admin/admin.module'; import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module'; +import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; +import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { MarketDataModule as MarketDataServiceModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; @@ -13,7 +15,9 @@ import { MarketDataController } from './market-data.controller'; AdminModule, MarketDataServiceModule, SymbolModule, - SymbolProfileModule + SymbolProfileModule, + TransformDataSourceInRequestModule, + TransformDataSourceInResponseModule ] }) export class MarketDataModule {} diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index b3b1d3410..2e58a4ef5 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -416,7 +416,6 @@ export abstract class PortfolioCalculator { dividendInBaseCurrency: totalDividendInBaseCurrency, fee: item.fee, feeInBaseCurrency: item.feeInBaseCurrency, - firstBuyDate: item.firstBuyDate, grossPerformance: !hasErrors ? (grossPerformance ?? null) : null, grossPerformancePercentage: !hasErrors ? (grossPerformancePercentage ?? null) @@ -446,7 +445,6 @@ export abstract class PortfolioCalculator { quantity: item.quantity, symbol: item.symbol, tags: item.tags, - transactionCount: item.transactionCount, valueInBaseCurrency: new Big(marketPriceInBaseCurrency).mul( item.quantity ) @@ -1004,11 +1002,9 @@ export abstract class PortfolioCalculator { fee: oldAccumulatedSymbol.fee.plus(fee), feeInBaseCurrency: oldAccumulatedSymbol.feeInBaseCurrency.plus(feeInBaseCurrency), - firstBuyDate: oldAccumulatedSymbol.firstBuyDate, includeInHoldings: oldAccumulatedSymbol.includeInHoldings, quantity: newQuantity, - tags: oldAccumulatedSymbol.tags.concat(tags), - transactionCount: oldAccumulatedSymbol.transactionCount + 1 + tags: oldAccumulatedSymbol.tags.concat(tags) }; } else { currentTransactionPointItem = { @@ -1024,11 +1020,9 @@ export abstract class PortfolioCalculator { averagePrice: unitPrice, dateOfFirstActivity: date, dividend: new Big(0), - firstBuyDate: date, includeInHoldings: INVESTMENT_ACTIVITY_TYPES.includes(type), investment: unitPrice.mul(quantity).mul(factor), - quantity: quantity.mul(factor), - transactionCount: 1 + quantity: quantity.mul(factor) }; } diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts index a1021a57b..52c8489dd 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts @@ -153,7 +153,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('3.2'), feeInBaseCurrency: new Big('3.2'), - firstBuyDate: '2021-11-22', grossPerformance: new Big('36.6'), grossPerformancePercentage: new Big('0.07706261539956593567'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -179,7 +178,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '474.93846153846153846154' ), - transactionCount: 2, valueInBaseCurrency: new Big('595.6') } ], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index 002730e32..3998b081d 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -169,7 +169,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('3.2'), feeInBaseCurrency: new Big('3.2'), - firstBuyDate: '2021-11-22', grossPerformance: new Big('-12.6'), grossPerformancePercentage: new Big('-0.04408677396780965649'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -193,7 +192,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '285.80000000000000396627' ), - transactionCount: 3, valueInBaseCurrency: new Big('0') } ], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts index e4ba70158..acd0d0b2e 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -153,7 +153,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('3.2'), feeInBaseCurrency: new Big('3.2'), - firstBuyDate: '2021-11-22', grossPerformance: new Big('-12.6'), grossPerformancePercentage: new Big('-0.0440867739678096571'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -177,7 +176,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('285.8'), timeWeightedInvestmentWithCurrencyEffect: new Big('285.8'), - transactionCount: 2, valueInBaseCurrency: new Big('0') } ], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts index e6cae7865..652e72db0 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts @@ -143,7 +143,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('1.55'), feeInBaseCurrency: new Big('1.55'), - firstBuyDate: '2021-11-30', grossPerformance: new Big('24.6'), grossPerformancePercentage: new Big('0.09004392386530014641'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -173,7 +172,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('273.2'), timeWeightedInvestmentWithCurrencyEffect: new Big('273.2'), - transactionCount: 1, valueInBaseCurrency: new Big('297.8') } ], 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 6cc58a70f..055356325 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 @@ -204,7 +204,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('4.46'), feeInBaseCurrency: new Big('4.46'), - firstBuyDate: '2021-12-12', grossPerformance: new Big('-1458.72'), grossPerformancePercentage: new Big('-0.03273724696701543726'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -228,7 +227,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('44558.42'), timeWeightedInvestmentWithCurrencyEffect: new Big('44558.42'), - transactionCount: 1, valueInBaseCurrency: new Big('43099.7') } ], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index 41f1d80a8..a70cc2986 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -167,7 +167,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('0'), feeInBaseCurrency: new Big('0'), - firstBuyDate: '2015-01-01', grossPerformance: new Big('27172.74').mul(0.97373), grossPerformancePercentage: new Big('0.4241983590271396608571'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -195,7 +194,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '636.79389574611155533947' ), - transactionCount: 2, valueInBaseCurrency: new Big('13298.425356') } ], 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 b8cecb350..64882061f 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 @@ -204,7 +204,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('4.46'), feeInBaseCurrency: new Big('4.46'), - firstBuyDate: '2021-12-12', grossPerformance: new Big('-1458.72'), grossPerformancePercentage: new Big('-0.03273724696701543726'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -228,7 +227,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('44558.42'), timeWeightedInvestmentWithCurrencyEffect: new Big('44558.42'), - transactionCount: 1, valueInBaseCurrency: new Big('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 bbcaba294..a53ebcf05 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 @@ -239,7 +239,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big(0), fee: new Big(0), feeInBaseCurrency: new Big(0), - firstBuyDate: '2023-12-31', grossPerformance: new Big(0), grossPerformancePercentage: new Big(0), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -277,7 +276,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '852.45231607629427792916' ), - transactionCount: 2, valueInBaseCurrency: new Big(1820) }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts index e438d9c6d..9b48a1324 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts @@ -149,7 +149,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('1'), feeInBaseCurrency: new Big('0.9238'), - firstBuyDate: '2023-01-03', grossPerformance: new Big('27.33').mul(0.8854), grossPerformancePercentage: new Big('0.3066651705565529623'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -173,7 +172,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('89.12').mul(0.8854), timeWeightedInvestmentWithCurrencyEffect: new Big('82.329056'), - transactionCount: 1, valueInBaseCurrency: new Big('103.10483') } ], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts index 88895b8c6..b19adb642 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -139,7 +139,6 @@ describe('PortfolioCalculator', () => { dividend: new Big('0.62'), dividendInBaseCurrency: new Big('0.62'), fee: new Big('19'), - firstBuyDate: '2021-09-16', grossPerformance: new Big('33.25'), grossPerformancePercentage: new Big('0.11136043941322258691'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -163,8 +162,7 @@ describe('PortfolioCalculator', () => { }, quantity: new Big('1'), symbol: 'MSFT', - tags: [], - transactionCount: 2 + tags: [] } ], totalFeesWithCurrencyEffect: new Big('19'), diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 8c0b1af6a..fecf17011 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -149,7 +149,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('4.25'), feeInBaseCurrency: new Big('4.25'), - firstBuyDate: '2022-03-07', grossPerformance: new Big('21.93'), grossPerformancePercentage: new Big('0.15113417083448194384'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -175,7 +174,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '145.10285714285714285714' ), - transactionCount: 2, valueInBaseCurrency: new Big('87.8') } ], 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 c4850db66..adbb5c3ff 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 @@ -202,7 +202,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('0'), feeInBaseCurrency: new Big('0'), - firstBuyDate: '2022-03-07', grossPerformance: new Big('19.86'), grossPerformancePercentage: new Big('0.13100263852242744063'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -226,7 +225,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('151.6'), timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'), - transactionCount: 2, valueInBaseCurrency: new Big('0') } ], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts index 5e73841ce..6fc94622f 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts @@ -125,7 +125,6 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0'), fee: new Big('0'), feeInBaseCurrency: new Big('0'), - firstBuyDate: '2022-01-01', grossPerformance: new Big('0'), grossPerformancePercentage: new Big('0'), grossPerformancePercentageWithCurrencyEffect: new Big('0'), @@ -147,7 +146,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('500000'), timeWeightedInvestmentWithCurrencyEffect: new Big('500000'), - transactionCount: 1, valueInBaseCurrency: new Big('500000') } ], diff --git a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts index ab2351f11..7f3f54ff5 100644 --- a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts @@ -11,17 +11,10 @@ export interface TransactionPointSymbol { dividend: Big; fee: Big; feeInBaseCurrency: Big; - - /** @deprecated use dateOfFirstActivity instead */ - firstBuyDate: string; - includeInHoldings: boolean; investment: Big; quantity: Big; skipErrors: boolean; symbol: string; tags?: Tag[]; - - /** @deprecated use activitiesCount instead */ - transactionCount: number; } diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 03796dad6..b8aefe0ac 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -195,11 +195,13 @@ export class PortfolioController { 'excludedAccountsAndActivities', 'fees', 'filteredValueInBaseCurrency', + 'fireWealth', 'grossPerformance', 'grossPerformanceWithCurrencyEffect', 'interestInBaseCurrency', 'items', 'liabilities', + 'liabilitiesInBaseCurrency', 'netPerformance', 'netPerformanceWithCurrencyEffect', 'totalBuy', @@ -329,7 +331,7 @@ export class PortfolioController { types: ['DIVIDEND'] }); - let dividends = await this.portfolioService.getDividends({ + let dividends = this.portfolioService.getDividends({ activities, groupBy }); diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 20016e67f..7be375473 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -233,7 +233,6 @@ export class PortfolioService { account.currency, userCurrency ), - transactionCount: activitiesCount, value: this.exchangeRateDataService.toCurrency( valueInBaseCurrency, userCurrency, @@ -284,7 +283,6 @@ export class PortfolioService { let totalDividendInBaseCurrency = new Big(0); let totalInterestInBaseCurrency = new Big(0); let totalValueInBaseCurrency = new Big(0); - let transactionCount = 0; for (const account of accounts) { activitiesCount += account.activitiesCount; @@ -301,8 +299,6 @@ export class PortfolioService { totalValueInBaseCurrency = totalValueInBaseCurrency.plus( account.valueInBaseCurrency ); - - transactionCount += account.transactionCount; } for (const account of accounts) { @@ -317,7 +313,6 @@ export class PortfolioService { return { accounts, activitiesCount, - transactionCount, totalBalanceInBaseCurrency: totalBalanceInBaseCurrency.toNumber(), totalDividendInBaseCurrency: totalDividendInBaseCurrency.toNumber(), totalInterestInBaseCurrency: totalInterestInBaseCurrency.toNumber(), @@ -325,13 +320,13 @@ export class PortfolioService { }; } - public async getDividends({ + public getDividends({ activities, groupBy }: { activities: Activity[]; groupBy?: GroupBy; - }): Promise { + }): InvestmentItem[] { let dividends = activities.map(({ currency, date, value }) => { return { date: format(date, DATE_FORMAT), @@ -576,8 +571,8 @@ export class PortfolioService { for (const { activitiesCount, currency, + dateOfFirstActivity, dividend, - firstBuyDate, grossPerformance, grossPerformanceWithCurrencyEffect, grossPerformancePercentage, @@ -591,7 +586,6 @@ export class PortfolioService { quantity, symbol, tags, - transactionCount, valueInBaseCurrency } of positions) { if (isFilteredByClosedHoldings === true) { @@ -625,7 +619,6 @@ export class PortfolioService { marketPrice, symbol, tags, - transactionCount, allocationInPercentage: filteredValueInBaseCurrency.eq(0) ? 0 : valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(), @@ -633,7 +626,7 @@ export class PortfolioService { assetSubClass: assetProfile.assetSubClass, countries: assetProfile.countries, dataSource: assetProfile.dataSource, - dateOfFirstActivity: parseDate(firstBuyDate), + dateOfFirstActivity: parseDate(dateOfFirstActivity), dividend: dividend?.toNumber() ?? 0, grossPerformance: grossPerformance?.toNumber() ?? 0, grossPerformancePercent: grossPerformancePercentage?.toNumber() ?? 0, @@ -801,9 +794,9 @@ export class PortfolioService { activitiesCount, averagePrice, currency, + dateOfFirstActivity, dividendInBaseCurrency, feeInBaseCurrency, - firstBuyDate, grossPerformance, grossPerformancePercentage, grossPerformancePercentageWithCurrencyEffect, @@ -828,7 +821,10 @@ export class PortfolioService { }); const dividendYieldPercent = getAnnualizedPerformancePercent({ - daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), + daysInMarket: differenceInDays( + new Date(), + parseDate(dateOfFirstActivity) + ), netPerformancePercentage: timeWeightedInvestment.eq(0) ? new Big(0) : dividendInBaseCurrency.div(timeWeightedInvestment) @@ -836,7 +832,10 @@ export class PortfolioService { const dividendYieldPercentWithCurrencyEffect = getAnnualizedPerformancePercent({ - daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), + daysInMarket: differenceInDays( + new Date(), + parseDate(dateOfFirstActivity) + ), netPerformancePercentage: timeWeightedInvestmentWithCurrencyEffect.eq(0) ? new Big(0) : dividendInBaseCurrency.div(timeWeightedInvestmentWithCurrencyEffect) @@ -845,7 +844,7 @@ export class PortfolioService { const historicalData = await this.dataProviderService.getHistorical( [{ dataSource, symbol }], 'day', - parseISO(firstBuyDate), + parseISO(dateOfFirstActivity), new Date() ); @@ -910,7 +909,7 @@ export class PortfolioService { // Add historical entry for buy date, if no historical data available historicalDataArray.push({ averagePrice: activitiesOfHolding[0].unitPriceInAssetProfileCurrency, - date: firstBuyDate, + date: dateOfFirstActivity, marketPrice: activitiesOfHolding[0].unitPriceInAssetProfileCurrency, quantity: activitiesOfHolding[0].quantity }); @@ -924,6 +923,7 @@ export class PortfolioService { return { activitiesCount, + dateOfFirstActivity, marketPrice, marketPriceMax, marketPriceMin, @@ -931,7 +931,6 @@ export class PortfolioService { tags, averagePrice: averagePrice.toNumber(), dataProviderInfo: portfolioCalculator.getDataProviderInfos()?.[0], - dateOfFirstActivity: firstBuyDate, dividendInBaseCurrency: dividendInBaseCurrency.toNumber(), dividendYieldPercent: dividendYieldPercent.toNumber(), dividendYieldPercentWithCurrencyEffect: @@ -1690,7 +1689,6 @@ export class PortfolioService { sectors: [], symbol: currency, tags: [], - transactionCount: 0, valueInBaseCurrency: balance }; } diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index b38b07bb4..689ee3e6a 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -35,7 +35,7 @@ export class SubscriptionService { this.stripe = new Stripe( this.configurationService.get('STRIPE_SECRET_KEY'), { - apiVersion: '2025-12-15.clover' + apiVersion: '2026-01-28.clover' } ); } @@ -100,7 +100,6 @@ export class SubscriptionService { ); return { - sessionId: session.id, sessionUrl: session.url }; } diff --git a/apps/api/src/helper/object.helper.spec.ts b/apps/api/src/helper/object.helper.spec.ts index e1ec81b8f..ed821390f 100644 --- a/apps/api/src/helper/object.helper.spec.ts +++ b/apps/api/src/helper/object.helper.spec.ts @@ -1,4 +1,6 @@ -import { query, redactAttributes } from './object.helper'; +import { DEFAULT_REDACTED_PATHS } from '@ghostfolio/common/config'; + +import { query, redactPaths } from './object.helper'; describe('query', () => { it('should get market price from stock API response', () => { @@ -22,46 +24,38 @@ describe('query', () => { describe('redactAttributes', () => { it('should redact provided attributes', () => { - expect(redactAttributes({ object: {}, options: [] })).toStrictEqual({}); + expect(redactPaths({ object: {}, paths: [] })).toStrictEqual({}); - expect( - redactAttributes({ object: { value: 1000 }, options: [] }) - ).toStrictEqual({ value: 1000 }); + expect(redactPaths({ object: { value: 1000 }, paths: [] })).toStrictEqual({ + value: 1000 + }); expect( - redactAttributes({ + redactPaths({ object: { value: 1000 }, - options: [{ attribute: 'value', valueMap: { '*': null } }] + paths: ['value'] }) ).toStrictEqual({ value: null }); expect( - redactAttributes({ + redactPaths({ object: { value: 'abc' }, - options: [{ attribute: 'value', valueMap: { abc: 'xyz' } }] + paths: ['value'], + valueMap: { abc: 'xyz' } }) ).toStrictEqual({ value: 'xyz' }); expect( - redactAttributes({ + redactPaths({ object: { data: [{ value: 'a' }, { value: 'b' }] }, - options: [{ attribute: 'value', valueMap: { a: 1, b: 2 } }] + paths: ['data[*].value'], + valueMap: { a: 1, b: 2 } }) ).toStrictEqual({ data: [{ value: 1 }, { value: 2 }] }); - expect( - redactAttributes({ - object: { value1: 'a', value2: 'b' }, - options: [ - { attribute: 'value1', valueMap: { a: 'x' } }, - { attribute: 'value2', valueMap: { '*': 'y' } } - ] - }) - ).toStrictEqual({ value1: 'x', value2: 'y' }); - console.time('redactAttributes execution time'); expect( - redactAttributes({ + redactPaths({ object: { accounts: { '2e937c05-657c-4de9-8fb3-0813a2245f26': { @@ -117,6 +111,7 @@ describe('redactAttributes', () => { hasError: false, holdings: { 'AAPL.US': { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -136,7 +131,6 @@ describe('redactAttributes', () => { marketPrice: 220.79, symbol: 'AAPL.US', tags: [], - transactionCount: 1, allocationInPercentage: 0.044900865255793135, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -169,6 +163,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.0694356974830054 }, 'ALV.DE': { + activitiesCount: 2, currency: 'EUR', markets: { UNKNOWN: 0, @@ -188,7 +183,6 @@ describe('redactAttributes', () => { marketPrice: 296.5, symbol: 'ALV.DE', tags: [], - transactionCount: 2, allocationInPercentage: 0.026912563036519527, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -216,6 +210,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.04161818652826481 }, AMZN: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -235,7 +230,6 @@ describe('redactAttributes', () => { marketPrice: 187.99, symbol: 'AMZN', tags: [], - transactionCount: 1, allocationInPercentage: 0.07646101417126275, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -268,6 +262,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.11824101426541227 }, bitcoin: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 36985.0332704, @@ -293,7 +288,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 1, allocationInPercentage: 0.15042891393226654, assetClass: 'LIQUIDITY', assetSubClass: 'CRYPTOCURRENCY', @@ -319,6 +313,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.232626620912395 }, BONDORA_GO_AND_GROW: { + activitiesCount: 5, currency: 'EUR', markets: { UNKNOWN: 2231.644722160232, @@ -344,7 +339,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 5, allocationInPercentage: 0.009076749759365777, assetClass: 'FIXED_INCOME', assetSubClass: 'BOND', @@ -370,6 +364,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.014036487867880205 }, FRANKLY95P: { + activitiesCount: 6, currency: 'CHF', markets: { UNKNOWN: 0, @@ -395,7 +390,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 6, allocationInPercentage: 0.09095764645669335, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -494,6 +488,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.14065892911313693 }, MSFT: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -513,7 +508,6 @@ describe('redactAttributes', () => { marketPrice: 428.02, symbol: 'MSFT', tags: [], - transactionCount: 1, allocationInPercentage: 0.05222646409742627, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -546,6 +540,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08076416659271518 }, TSLA: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -565,7 +560,6 @@ describe('redactAttributes', () => { marketPrice: 260.46, symbol: 'TSLA', tags: [], - transactionCount: 1, allocationInPercentage: 0.1589050142378352, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -598,6 +592,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.2457342510950259 }, VTI: { + activitiesCount: 5, currency: 'USD', markets: { UNKNOWN: 0, @@ -617,7 +612,6 @@ describe('redactAttributes', () => { marketPrice: 282.05, symbol: 'VTI', tags: [], - transactionCount: 5, allocationInPercentage: 0.057358979326040366, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -770,6 +764,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08870120238725339 }, 'VWRL.SW': { + activitiesCount: 5, currency: 'CHF', markets: { UNKNOWN: 0, @@ -789,7 +784,6 @@ describe('redactAttributes', () => { marketPrice: 117.62, symbol: 'VWRL.SW', tags: [], - transactionCount: 5, allocationInPercentage: 0.09386983901959013, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -1178,6 +1172,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.145162408515095 }, 'XDWD.DE': { + activitiesCount: 1, currency: 'EUR', markets: { UNKNOWN: 0, @@ -1197,7 +1192,6 @@ describe('redactAttributes', () => { marketPrice: 105.72, symbol: 'XDWD.DE', tags: [], - transactionCount: 1, allocationInPercentage: 0.03598477442100562, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -1456,6 +1450,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.055647656152211074 }, USD: { + activitiesCount: 0, currency: 'USD', allocationInPercentage: 0.20291717628620132, assetClass: 'LIQUIDITY', @@ -1478,7 +1473,6 @@ describe('redactAttributes', () => { sectors: [], symbol: 'USD', tags: [], - transactionCount: 0, valueInBaseCurrency: 49890, valueInPercentage: 0.3137956381563603 } @@ -1564,34 +1558,7 @@ describe('redactAttributes', () => { currentNetWorth: null } }, - options: [ - 'balance', - 'balanceInBaseCurrency', - 'comment', - 'convertedBalance', - 'dividendInBaseCurrency', - 'fee', - 'feeInBaseCurrency', - 'grossPerformance', - 'grossPerformanceWithCurrencyEffect', - 'investment', - 'netPerformance', - 'netPerformanceWithCurrencyEffect', - 'quantity', - 'symbolMapping', - 'totalBalanceInBaseCurrency', - 'totalValueInBaseCurrency', - 'unitPrice', - 'value', - 'valueInBaseCurrency' - ].map((attribute) => { - return { - attribute, - valueMap: { - '*': null - } - }; - }) + paths: DEFAULT_REDACTED_PATHS }) ).toStrictEqual({ accounts: { @@ -1648,6 +1615,7 @@ describe('redactAttributes', () => { hasError: false, holdings: { 'AAPL.US': { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -1667,7 +1635,6 @@ describe('redactAttributes', () => { marketPrice: 220.79, symbol: 'AAPL.US', tags: [], - transactionCount: 1, allocationInPercentage: 0.044900865255793135, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -1681,7 +1648,7 @@ describe('redactAttributes', () => { ], dataSource: 'EOD_HISTORICAL_DATA', dateOfFirstActivity: '2021-11-30T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3183066634822068, grossPerformancePercentWithCurrencyEffect: 0.3183066634822068, @@ -1700,6 +1667,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.0694356974830054 }, 'ALV.DE': { + activitiesCount: 2, currency: 'EUR', markets: { UNKNOWN: 0, @@ -1719,7 +1687,6 @@ describe('redactAttributes', () => { marketPrice: 296.5, symbol: 'ALV.DE', tags: [], - transactionCount: 2, allocationInPercentage: 0.026912563036519527, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -1728,7 +1695,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2021-04-22T22:00:00.000Z', - dividend: 192, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3719230057375532, grossPerformancePercentWithCurrencyEffect: 0.2650716044872953, @@ -1747,6 +1714,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.04161818652826481 }, AMZN: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -1766,7 +1734,6 @@ describe('redactAttributes', () => { marketPrice: 187.99, symbol: 'AMZN', tags: [], - transactionCount: 1, allocationInPercentage: 0.07646101417126275, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -1780,7 +1747,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2018-09-30T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.8594552890963852, grossPerformancePercentWithCurrencyEffect: 0.8594552890963852, @@ -1799,6 +1766,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.11824101426541227 }, bitcoin: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 36985.0332704, @@ -1824,14 +1792,13 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 1, allocationInPercentage: 0.15042891393226654, assetClass: 'LIQUIDITY', assetSubClass: 'CRYPTOCURRENCY', countries: [], dataSource: 'COINGECKO', dateOfFirstActivity: '2017-08-15T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 17.4925166352, grossPerformancePercentWithCurrencyEffect: 17.4925166352, @@ -1850,6 +1817,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.232626620912395 }, BONDORA_GO_AND_GROW: { + activitiesCount: 5, currency: 'EUR', markets: { UNKNOWN: 2231.644722160232, @@ -1875,14 +1843,13 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 5, allocationInPercentage: 0.009076749759365777, assetClass: 'FIXED_INCOME', assetSubClass: 'BOND', countries: [], dataSource: 'MANUAL', dateOfFirstActivity: '2021-01-31T23:00:00.000Z', - dividend: 11.45, + dividend: null, grossPerformance: null, grossPerformancePercent: 0, grossPerformancePercentWithCurrencyEffect: -0.06153834320225245, @@ -1901,6 +1868,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.014036487867880205 }, FRANKLY95P: { + activitiesCount: 6, currency: 'CHF', markets: { UNKNOWN: 0, @@ -1926,7 +1894,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 6, allocationInPercentage: 0.09095764645669335, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -1986,7 +1953,7 @@ describe('redactAttributes', () => { ], dataSource: 'MANUAL', dateOfFirstActivity: '2021-03-31T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.27579517683678895, grossPerformancePercentWithCurrencyEffect: 0.458553421589667, @@ -2005,6 +1972,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.14065892911313693 }, MSFT: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -2024,7 +1992,6 @@ describe('redactAttributes', () => { marketPrice: 428.02, symbol: 'MSFT', tags: [], - transactionCount: 1, allocationInPercentage: 0.05222646409742627, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -2038,7 +2005,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2023-01-02T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.7865431171216295, grossPerformancePercentWithCurrencyEffect: 0.7865431171216295, @@ -2057,6 +2024,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08076416659271518 }, TSLA: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -2076,7 +2044,6 @@ describe('redactAttributes', () => { marketPrice: 260.46, symbol: 'TSLA', tags: [], - transactionCount: 1, allocationInPercentage: 0.1589050142378352, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -2090,7 +2057,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2017-01-02T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 17.184314638161936, grossPerformancePercentWithCurrencyEffect: 17.184314638161936, @@ -2109,6 +2076,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.2457342510950259 }, VTI: { + activitiesCount: 5, currency: 'USD', markets: { UNKNOWN: 0, @@ -2128,7 +2096,6 @@ describe('redactAttributes', () => { marketPrice: 282.05, symbol: 'VTI', tags: [], - transactionCount: 5, allocationInPercentage: 0.057358979326040366, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -2172,7 +2139,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2019-02-28T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.8832083851170418, grossPerformancePercentWithCurrencyEffect: 0.8832083851170418, @@ -2281,6 +2248,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08870120238725339 }, 'VWRL.SW': { + activitiesCount: 5, currency: 'CHF', markets: { UNKNOWN: 0, @@ -2300,7 +2268,6 @@ describe('redactAttributes', () => { marketPrice: 117.62, symbol: 'VWRL.SW', tags: [], - transactionCount: 5, allocationInPercentage: 0.09386983901959013, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -2567,7 +2534,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2018-02-28T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3683200415015591, grossPerformancePercentWithCurrencyEffect: 0.5806366182968891, @@ -2681,6 +2648,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.145162408515095 }, 'XDWD.DE': { + activitiesCount: 1, currency: 'EUR', markets: { UNKNOWN: 0, @@ -2700,7 +2668,6 @@ describe('redactAttributes', () => { marketPrice: 105.72, symbol: 'XDWD.DE', tags: [], - transactionCount: 1, allocationInPercentage: 0.03598477442100562, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -2846,7 +2813,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2021-08-18T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3474381850624522, grossPerformancePercentWithCurrencyEffect: 0.28744846894552306, @@ -2959,12 +2926,13 @@ describe('redactAttributes', () => { valueInPercentage: 0.055647656152211074 }, USD: { + activitiesCount: 0, currency: 'USD', allocationInPercentage: 0.20291717628620132, assetClass: 'LIQUIDITY', assetSubClass: 'CASH', countries: [], - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0, grossPerformancePercentWithCurrencyEffect: 0, @@ -2981,7 +2949,6 @@ describe('redactAttributes', () => { sectors: [], symbol: 'USD', tags: [], - transactionCount: 0, valueInBaseCurrency: null, valueInPercentage: 0.3137956381563603 } diff --git a/apps/api/src/helper/object.helper.ts b/apps/api/src/helper/object.helper.ts index 6bb6579d2..350d5fe04 100644 --- a/apps/api/src/helper/object.helper.ts +++ b/apps/api/src/helper/object.helper.ts @@ -1,6 +1,6 @@ -import { Big } from 'big.js'; +import fastRedact from 'fast-redact'; import jsonpath from 'jsonpath'; -import { cloneDeep, isArray, isObject } from 'lodash'; +import { cloneDeep, isObject } from 'lodash'; export function hasNotDefinedValuesInObject(aObject: Object): boolean { for (const key in aObject) { @@ -42,60 +42,29 @@ export function query({ return jsonpath.query(object, pathExpression); } -export function redactAttributes({ - isFirstRun = true, +export function redactPaths({ object, - options + paths, + valueMap }: { - isFirstRun?: boolean; object: any; - options: { attribute: string; valueMap: { [key: string]: any } }[]; + paths: fastRedact.RedactOptions['paths']; + valueMap?: { [key: string]: any }; }): any { - if (!object || !options?.length) { - return object; - } - - // Create deep clone - const redactedObject = isFirstRun - ? JSON.parse(JSON.stringify(object)) - : object; - - for (const option of options) { - if (redactedObject.hasOwnProperty(option.attribute)) { - if (option.valueMap['*'] || option.valueMap['*'] === null) { - redactedObject[option.attribute] = option.valueMap['*']; - } else if (option.valueMap[redactedObject[option.attribute]]) { - redactedObject[option.attribute] = - option.valueMap[redactedObject[option.attribute]]; - } - } else { - // If the attribute is not present on the current object, - // check if it exists on any nested objects - for (const property in redactedObject) { - if (isArray(redactedObject[property])) { - redactedObject[property] = redactedObject[property].map( - (currentObject) => { - return redactAttributes({ - options, - isFirstRun: false, - object: currentObject - }); - } - ); - } else if ( - isObject(redactedObject[property]) && - !(redactedObject[property] instanceof Big) - ) { - // Recursively call the function on the nested object - redactedObject[property] = redactAttributes({ - options, - isFirstRun: false, - object: redactedObject[property] - }); + const redact = fastRedact({ + paths, + censor: (value) => { + if (valueMap) { + if (valueMap[value]) { + return valueMap[value]; + } else { + return value; } + } else { + return null; } } - } + }); - return redactedObject; + return JSON.parse(redact(object)); } diff --git a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts index 5ecf7c48d..60b994cac 100644 --- a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts +++ b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts @@ -1,5 +1,8 @@ -import { redactAttributes } from '@ghostfolio/api/helper/object.helper'; -import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; +import { redactPaths } from '@ghostfolio/api/helper/object.helper'; +import { + DEFAULT_REDACTED_PATHS, + HEADER_KEY_IMPERSONATION +} from '@ghostfolio/common/config'; import { hasReadRestrictedAccessPermission, isRestrictedView @@ -39,40 +42,9 @@ export class RedactValuesInResponseInterceptor implements NestInterceptor< }) || isRestrictedView(user) ) { - data = redactAttributes({ + data = redactPaths({ object: data, - options: [ - 'balance', - 'balanceInBaseCurrency', - 'comment', - 'convertedBalance', - 'dividendInBaseCurrency', - 'fee', - 'feeInBaseCurrency', - 'grossPerformance', - 'grossPerformanceWithCurrencyEffect', - 'interestInBaseCurrency', - 'investment', - 'netPerformance', - 'netPerformanceWithCurrencyEffect', - 'quantity', - 'symbolMapping', - 'totalBalanceInBaseCurrency', - 'totalDividendInBaseCurrency', - 'totalInterestInBaseCurrency', - 'totalValueInBaseCurrency', - 'unitPrice', - 'unitPriceInAssetProfileCurrency', - 'value', - 'valueInBaseCurrency' - ].map((attribute) => { - return { - attribute, - valueMap: { - '*': null - } - }; - }) + paths: DEFAULT_REDACTED_PATHS }); } diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index 9af256671..eaa6dd08c 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -1,4 +1,4 @@ -import { redactAttributes } from '@ghostfolio/api/helper/object.helper'; +import { redactPaths } from '@ghostfolio/api/helper/object.helper'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { encodeDataSource } from '@ghostfolio/common/helper'; @@ -58,13 +58,18 @@ export class TransformDataSourceInResponseInterceptor< } } - data = redactAttributes({ + data = redactPaths({ + valueMap, object: data, - options: [ - { - valueMap, - attribute: 'dataSource' - } + paths: [ + 'activities[*].SymbolProfile.dataSource', + 'benchmarks[*].dataSource', + 'fearAndGreedIndex.CRYPTOCURRENCIES.dataSource', + 'fearAndGreedIndex.STOCKS.dataSource', + 'holdings[*].dataSource', + 'items[*].dataSource', + 'SymbolProfile.dataSource', + 'watchlist[*].dataSource' ] }); } 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 65bcd6c06..c83e35503 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 @@ -135,10 +135,10 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { shortName, symbol }: { - longName: Price['longName']; - quoteType: Price['quoteType']; - shortName: Price['shortName']; - symbol: Price['symbol']; + longName?: Price['longName']; + quoteType?: Price['quoteType']; + shortName?: Price['shortName']; + symbol?: Price['symbol']; }) { let name = longName; @@ -206,17 +206,26 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { ); if (['ETF', 'MUTUALFUND'].includes(assetSubClass)) { - response.sectors = []; - - for (const sectorWeighting of assetProfile.topHoldings - ?.sectorWeightings ?? []) { - for (const [sector, weight] of Object.entries(sectorWeighting)) { - response.sectors.push({ + response.holdings = + assetProfile.topHoldings?.holdings?.map( + ({ holdingName, holdingPercent }) => { + return { + name: this.formatName({ longName: holdingName }), + weight: holdingPercent + }; + } + ) ?? []; + + response.sectors = ( + assetProfile.topHoldings?.sectorWeightings ?? [] + ).flatMap((sectorWeighting) => { + return Object.entries(sectorWeighting).map(([sector, weight]) => { + return { name: this.parseSector(sector), weight: weight as number - }); - } - } + }; + }); + }); } else if ( assetSubClass === 'STOCK' && assetProfile.summaryProfile?.country diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts index b40043cc8..380fb69cb 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts @@ -80,6 +80,7 @@ import { AccountDetailDialogParams } from './interfaces/interfaces'; export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public accountBalances: AccountBalancesResponse['balances']; public activities: OrderWithAccount[]; + public activitiesCount: number; public balance: number; public balancePrecision = 2; public currency: string; @@ -100,7 +101,6 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public sortColumn = 'date'; public sortDirection: SortDirection = 'desc'; public totalItems: number; - public transactionCount: number; public user: User; public valueInBaseCurrency: number; @@ -215,16 +215,17 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe( ({ + activitiesCount, balance, currency, dividendInBaseCurrency, interestInBaseCurrency, name, platform, - transactionCount, value, valueInBaseCurrency }) => { + this.activitiesCount = activitiesCount; this.balance = balance; if ( @@ -270,7 +271,6 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { this.name = name; this.platformName = platform?.name ?? '-'; - this.transactionCount = transactionCount; this.valueInBaseCurrency = valueInBaseCurrency; this.changeDetectorRef.markForCheck(); diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html index 07ea17038..15dd8f13a 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html @@ -82,7 +82,7 @@ >
- Activities
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 bc3b0d374..8f956b782 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 @@ -63,7 +63,7 @@ import { import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; -import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; +import { distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { AdminMarketDataService } from './admin-market-data.service'; import { GfAssetProfileDialogComponent } from './asset-profile-dialog/asset-profile-dialog.component'; @@ -482,32 +482,27 @@ export class GfAdminMarketDataComponent dialogRef .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ dataSource, symbol } = {}) => { - if (dataSource && symbol) { + .subscribe((result) => { + if (!result) { + this.router.navigate(['.'], { relativeTo: this.route }); + + return; + } + + const { addAssetProfile, dataSource, symbol } = result; + + if (addAssetProfile && dataSource && symbol) { this.adminService .addAssetProfile({ dataSource, symbol }) - .pipe( - switchMap(() => { - this.isLoading = true; - this.changeDetectorRef.markForCheck(); - - return this.adminService.fetchAdminMarketData({ - filters: this.activeFilters, - take: this.pageSize - }); - }), - takeUntil(this.unsubscribeSubject) - ) - .subscribe(({ marketData }) => { - this.dataSource = new MatTableDataSource(marketData); - this.dataSource.sort = this.sort; - this.isLoading = false; - - this.changeDetectorRef.markForCheck(); + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.loadData(); }); + } else { + this.loadData(); } - this.router.navigate(['.'], { relativeTo: this.route }); + this.onOpenAssetProfileDialog({ dataSource, symbol }); }); }); } diff --git a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts index 6c180b034..fbf8afa03 100644 --- a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts @@ -101,6 +101,7 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { public onSubmit() { if (this.mode === 'auto') { this.dialogRef.close({ + addAssetProfile: true, dataSource: this.createAssetProfileForm.get('searchSymbol').value.dataSource, symbol: this.createAssetProfileForm.get('searchSymbol').value.symbol @@ -127,10 +128,15 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { takeUntil(this.unsubscribeSubject) ) .subscribe(() => { - this.dialogRef.close(); + this.dialogRef.close({ + addAssetProfile: false, + dataSource: this.dataSourceForExchangeRates, + symbol: `${DEFAULT_CURRENCY}${currency}` + }); }); } else if (this.mode === 'manual') { this.dialogRef.close({ + addAssetProfile: true, dataSource: 'MANUAL', symbol: `${this.ghostfolioPrefix}${this.createAssetProfileForm.get('addSymbol').value}` }); diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index 6284f05fd..c0ccb0f64 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -73,6 +73,7 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './admin-overview.html' }) export class GfAdminOverviewComponent implements OnDestroy, OnInit { + public activitiesCount: number; public couponDuration: StringValue = '14 days'; public coupons: Coupon[]; public hasPermissionForSubscription: boolean; @@ -83,7 +84,6 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { public isDataGatheringEnabled: boolean; public permissions = permissions; public systemMessage: SystemMessage; - public transactionCount: number; public userCount: number; public user: User; public version: string; @@ -289,12 +289,12 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { this.adminService .fetchAdminData() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ settings, transactionCount, userCount, version }) => { + .subscribe(({ activitiesCount, settings, userCount, version }) => { + this.activitiesCount = activitiesCount; this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? []; this.isDataGatheringEnabled = settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false ? false : true; this.systemMessage = settings[PROPERTY_SYSTEM_MESSAGE] as SystemMessage; - this.transactionCount = transactionCount; this.userCount = userCount; this.version = version; diff --git a/apps/client/src/app/components/admin-overview/admin-overview.html b/apps/client/src/app/components/admin-overview/admin-overview.html index c47387f37..f0a6ea1d5 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -20,11 +20,11 @@
- @if (transactionCount && userCount) { + @if (activitiesCount && userCount) {
- {{ transactionCount / userCount | number: '1.2-2' }} + {{ activitiesCount / userCount | number: '1.2-2' }} per User
} 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 2ae3b1a57..d479f2037 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 @@ -57,7 +57,7 @@ import { import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { switchMap, takeUntil, tap } from 'rxjs/operators'; @Component({ imports: [ @@ -139,8 +139,25 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { ]; } - this.route.paramMap - .pipe(takeUntil(this.unsubscribeSubject)) + this.userService.stateChanged + .pipe( + takeUntil(this.unsubscribeSubject), + tap((state) => { + if (state?.user) { + this.user = state.user; + + this.defaultDateFormat = getDateFormatString( + this.user.settings.locale + ); + + this.hasPermissionToImpersonateAllUsers = hasPermission( + this.user.permissions, + permissions.impersonateAllUsers + ); + } + }), + switchMap(() => this.route.paramMap) + ) .subscribe((params) => { const userId = params.get('userId'); @@ -149,23 +166,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { } }); - this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((state) => { - if (state?.user) { - this.user = state.user; - - this.defaultDateFormat = getDateFormatString( - this.user.settings.locale - ); - - this.hasPermissionToImpersonateAllUsers = hasPermission( - this.user.permissions, - permissions.impersonateAllUsers - ); - } - }); - addIcons({ contractOutline, ellipsisHorizontal, @@ -208,10 +208,13 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { .deleteUser(aId) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { - this.fetchUsers(); + this.router.navigate(['..'], { relativeTo: this.route }); }); }, confirmType: ConfirmationDialogType.Warn, + discardFn: () => { + this.router.navigate(['..'], { relativeTo: this.route }); + }, title: $localize`Do you really want to delete this user?` }); } @@ -293,6 +296,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { >(GfUserDetailDialogComponent, { autoFocus: false, data: { + currentUserId: this.user?.id, deviceType: this.deviceType, hasPermissionForSubscription: this.hasPermissionForSubscription, locale: this.user?.settings?.locale, @@ -305,10 +309,14 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { dialogRef .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(() => { - this.router.navigate( - internalRoutes.adminControl.subRoutes.users.routerLink - ); + .subscribe((data) => { + if (data?.action === 'delete' && data?.userId) { + this.onDeleteUser(data.userId); + } else { + this.router.navigate( + internalRoutes.adminControl.subRoutes.users.routerLink + ); + } }); } } diff --git a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts index 7f03ea57f..2ecefc311 100644 --- a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts +++ b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1,6 +1,5 @@ import { getTooltipOptions, - getTooltipPositionerMapTop, getVerticalHoverLinePlugin } from '@ghostfolio/common/chart-helper'; import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; @@ -15,12 +14,14 @@ import { LineChartItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { ColorScheme } from '@ghostfolio/common/types'; +import { registerChartConfiguration } from '@ghostfolio/ui/chart'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, + type ElementRef, EventEmitter, Input, OnChanges, @@ -42,7 +43,7 @@ import { PointElement, TimeScale, Tooltip, - TooltipPosition + type TooltipOptions } from 'chart.js'; import 'chartjs-adapter-date-fns'; import annotationPlugin from 'chartjs-plugin-annotation'; @@ -78,7 +79,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { @Output() benchmarkChanged = new EventEmitter(); - @ViewChild('chartCanvas') chartCanvas; + @ViewChild('chartCanvas') chartCanvas: ElementRef; public chart: Chart<'line'>; public hasPermissionToAccessAdminControl: boolean; @@ -96,8 +97,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { Tooltip ); - Tooltip.positioners['top'] = (_elements, position: TooltipPosition) => - getTooltipPositionerMapTop(this.chart, position); + registerChartConfiguration(); addIcons({ arrowForwardOutline }); } @@ -157,8 +157,10 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { if (this.chartCanvas) { if (this.chart) { this.chart.data = data; + this.chart.options.plugins ??= {}; this.chart.options.plugins.tooltip = - this.getTooltipPluginConfiguration() as unknown; + this.getTooltipPluginConfiguration(); + this.chart.update(); } else { this.chart = new Chart(this.chartCanvas.nativeElement, { @@ -196,7 +198,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { verticalHoverLine: { color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` } - } as unknown, + }, responsive: true, scales: { x: { @@ -253,7 +255,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { } } - private getTooltipPluginConfiguration() { + private getTooltipPluginConfiguration(): Partial> { return { ...getTooltipOptions({ colorScheme: this.colorScheme, @@ -261,7 +263,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { unit: '%' }), mode: 'index', - position: 'top' as unknown, + position: 'top', xAlign: 'center', yAlign: 'bottom' }; 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 f9329dbfb..27df91a17 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 @@ -380,10 +380,10 @@ [deviceType]="data.deviceType" [hasPermissionToOpenDetails]="false" [locale]="user?.settings?.locale" + [showActivitiesCount]="false" [showAllocationInPercentage]="user?.settings?.isExperimentalFeatures" [showBalance]="false" [showFooter]="false" - [showTransactions]="false" [showValue]="false" [showValueInBaseCurrency]="false" /> diff --git a/apps/client/src/app/components/investment-chart/investment-chart.component.ts b/apps/client/src/app/components/investment-chart/investment-chart.component.ts index 5492ddd4c..53d4f5693 100644 --- a/apps/client/src/app/components/investment-chart/investment-chart.component.ts +++ b/apps/client/src/app/components/investment-chart/investment-chart.component.ts @@ -1,6 +1,5 @@ import { getTooltipOptions, - getTooltipPositionerMapTop, getVerticalHoverLinePlugin, transformTickToAbbreviation } from '@ghostfolio/common/chart-helper'; @@ -15,11 +14,13 @@ import { import { LineChartItem } from '@ghostfolio/common/interfaces'; import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; import { ColorScheme, GroupBy } from '@ghostfolio/common/types'; +import { registerChartConfiguration } from '@ghostfolio/ui/chart'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, + type ElementRef, Input, OnChanges, OnDestroy, @@ -34,12 +35,15 @@ import { LineController, LineElement, PointElement, + type ScriptableLineSegmentContext, TimeScale, Tooltip, - TooltipPosition + type TooltipOptions } from 'chart.js'; import 'chartjs-adapter-date-fns'; -import annotationPlugin from 'chartjs-plugin-annotation'; +import annotationPlugin, { + type AnnotationOptions +} from 'chartjs-plugin-annotation'; import { isAfter } from 'date-fns'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -62,7 +66,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { @Input() locale = getLocale(); @Input() savingsRate = 0; - @ViewChild('chartCanvas') chartCanvas; + @ViewChild('chartCanvas') chartCanvas: ElementRef; public chart: Chart<'bar' | 'line'>; private investments: InvestmentItem[]; @@ -81,8 +85,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { Tooltip ); - Tooltip.positioners['top'] = (_elements, position: TooltipPosition) => - getTooltipPositionerMapTop(this.chart, position); + registerChartConfiguration(); } public ngOnChanges() { @@ -121,12 +124,12 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { }), label: this.benchmarkDataLabel, segment: { - borderColor: (context: unknown) => + borderColor: (context) => this.isInFuture( context, `rgba(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b}, 0.67)` ), - borderDash: (context: unknown) => this.isInFuture(context, [2, 2]) + borderDash: (context) => this.isInFuture(context, [2, 2]) }, stepped: true }, @@ -143,12 +146,12 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { label: $localize`Total Amount`, pointRadius: 0, segment: { - borderColor: (context: unknown) => + borderColor: (context) => this.isInFuture( context, `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.67)` ), - borderDash: (context: unknown) => this.isInFuture(context, [2, 2]) + borderDash: (context) => this.isInFuture(context, [2, 2]) } } ] @@ -157,17 +160,14 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { if (this.chartCanvas) { if (this.chart) { this.chart.data = chartData; + this.chart.options.plugins ??= {}; this.chart.options.plugins.tooltip = - this.getTooltipPluginConfiguration() as unknown; + this.getTooltipPluginConfiguration(); - if ( - this.savingsRate && - // @ts-ignore - this.chart.options.plugins.annotation.annotations.savingsRate - ) { - // @ts-ignore - this.chart.options.plugins.annotation.annotations.savingsRate.value = - this.savingsRate; + const annotations = this.chart.options.plugins.annotation + .annotations as Record>; + if (this.savingsRate && annotations.savingsRate) { + annotations.savingsRate.value = this.savingsRate; } this.chart.update(); @@ -201,7 +201,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { color: 'white', content: $localize`Savings Rate`, display: true, - font: { size: '10px', weight: 'normal' }, + font: { size: 10, weight: 'normal' }, padding: { x: 4, y: 2 @@ -229,7 +229,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { verticalHoverLine: { color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` } - } as unknown, + }, responsive: true, scales: { x: { @@ -286,7 +286,9 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { } } - private getTooltipPluginConfiguration() { + private getTooltipPluginConfiguration(): Partial< + TooltipOptions<'bar' | 'line'> + > { return { ...getTooltipOptions({ colorScheme: this.colorScheme, @@ -296,13 +298,13 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { unit: this.isInPercent ? '%' : undefined }), mode: 'index', - position: 'top' as unknown, + position: 'top', xAlign: 'center', yAlign: 'bottom' }; } - private isInFuture(aContext: any, aValue: T) { + private isInFuture(aContext: ScriptableLineSegmentContext, aValue: T) { return isAfter(new Date(aContext?.p1?.parsed?.x), new Date()) ? aValue : undefined; 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 b922e7a54..ed46e8a02 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,4 +1,5 @@ export interface UserDetailDialogParams { + currentUserId: string; deviceType: string; hasPermissionForSubscription: boolean; locale: string; diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts index cdf977058..6f7f4ead6 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts @@ -1,6 +1,4 @@ import { AdminUserResponse } from '@ghostfolio/common/interfaces'; -import { GfDialogFooterComponent } from '@ghostfolio/ui/dialog-footer'; -import { GfDialogHeaderComponent } from '@ghostfolio/ui/dialog-header'; import { AdminService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -16,6 +14,10 @@ import { import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog'; +import { MatMenuModule } from '@angular/material/menu'; +import { IonIcon } from '@ionic/angular/standalone'; +import { addIcons } from 'ionicons'; +import { ellipsisVertical } from 'ionicons/icons'; import { EMPTY, Subject } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; @@ -25,11 +27,11 @@ import { UserDetailDialogParams } from './interfaces/interfaces'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'd-flex flex-column h-100' }, imports: [ - GfDialogFooterComponent, - GfDialogHeaderComponent, GfValueComponent, + IonIcon, MatButtonModule, - MatDialogModule + MatDialogModule, + MatMenuModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-user-detail-dialog', @@ -46,7 +48,11 @@ export class GfUserDetailDialogComponent implements OnDestroy, OnInit { private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: UserDetailDialogParams, public dialogRef: MatDialogRef - ) {} + ) { + addIcons({ + ellipsisVertical + }); + } public ngOnInit() { this.adminService @@ -66,6 +72,13 @@ export class GfUserDetailDialogComponent implements OnDestroy, OnInit { }); } + public deleteUser() { + this.dialogRef.close({ + action: 'delete', + userId: this.data.userId + }); + } + public onClose() { this.dialogRef.close(); } 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 60f6a2585..570dcf4d6 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 @@ -1,9 +1,28 @@ - - +
+ + + + +
@@ -103,7 +122,8 @@
- +
+ +
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 6c8146f77..f7e6541b5 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -38,6 +38,7 @@ import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-ba }) export class GfAccountsPageComponent implements OnDestroy, OnInit { public accounts: AccountModel[]; + public activitiesCount = 0; public deviceType: string; public hasImpersonationId: boolean; public hasPermissionToCreateAccount: boolean; @@ -45,7 +46,6 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { public routeQueryParams: Subscription; public totalBalanceInBaseCurrency = 0; public totalValueInBaseCurrency = 0; - public transactionCount = 0; public user: User; private unsubscribeSubject = new Subject(); @@ -128,14 +128,14 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { .subscribe( ({ accounts, + activitiesCount, totalBalanceInBaseCurrency, - totalValueInBaseCurrency, - transactionCount + totalValueInBaseCurrency }) => { this.accounts = accounts; + this.activitiesCount = activitiesCount; this.totalBalanceInBaseCurrency = totalBalanceInBaseCurrency; this.totalValueInBaseCurrency = totalValueInBaseCurrency; - this.transactionCount = transactionCount; if (this.accounts?.length <= 0) { this.router.navigate([], { queryParams: { createDialog: true } }); @@ -358,8 +358,8 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { private reset() { this.accounts = undefined; + this.activitiesCount = 0; this.totalBalanceInBaseCurrency = 0; this.totalValueInBaseCurrency = 0; - this.transactionCount = 0; } } diff --git a/apps/client/src/app/pages/accounts/accounts-page.html b/apps/client/src/app/pages/accounts/accounts-page.html index 6f29a4f7c..0c6b7b8f3 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.html +++ b/apps/client/src/app/pages/accounts/accounts-page.html @@ -4,6 +4,7 @@

Accounts

  • - Everything in -   - Basic, - plus: + Everything in Basic, plus:
  • diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index fc8a326c3..a6bec7df3 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -295,7 +295,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -358,14 +358,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Realment vol revocar aquest accés? @@ -878,14 +870,6 @@ 96 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs sense País @@ -1659,7 +1643,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -1675,7 +1659,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -2047,7 +2031,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -2123,7 +2107,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -2135,7 +2119,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -2235,7 +2219,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -2255,7 +2239,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2271,7 +2255,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2287,7 +2271,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2299,7 +2283,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2315,7 +2299,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2399,7 +2383,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2527,7 +2511,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -3448,7 +3432,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -3920,7 +3904,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4480,7 +4464,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4544,7 +4528,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -4576,7 +4560,7 @@ Rendiment absolut dels actius apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -4584,7 +4568,7 @@ Rendiment de l’actiu apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -4592,7 +4576,7 @@ Rendiment absolut de la moneda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -4600,7 +4584,7 @@ Rendiment de la moneda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -4608,7 +4592,7 @@ A dalt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -4616,7 +4600,7 @@ A baix apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -4624,7 +4608,7 @@ Evolució de la cartera apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -4632,7 +4616,7 @@ Cronologia de la inversió apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -4640,7 +4624,7 @@ Ratxa actual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4648,7 +4632,7 @@ Ratxa més llarga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4656,7 +4640,7 @@ Cronologia de dividends apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -4832,7 +4816,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4848,7 +4832,7 @@ Suport per correu electrònic i xat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4856,7 +4840,7 @@ Pagament únic, sense renovació automàtica. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -4876,7 +4860,7 @@ És gratuït. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -5305,7 +5289,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5593,7 +5577,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5944,6 +5928,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satèl·lit @@ -6857,7 +6849,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6969,7 +6961,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7379,7 +7371,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 6c2bd7900..44ee607c3 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -42,7 +42,7 @@ bitte apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -89,14 +89,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Möchtest du diese Zugangsberechtigung wirklich widerrufen? @@ -742,7 +734,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -874,7 +866,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -926,7 +918,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -938,7 +930,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1122,7 +1114,7 @@ Performance mit Währungseffekt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -1262,7 +1254,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1862,7 +1854,7 @@ Zeitstrahl der Investitionen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -1870,7 +1862,7 @@ Gewinner apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -1878,7 +1870,7 @@ Verlierer apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -2346,7 +2338,7 @@ kontaktiere uns apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2762,7 +2754,7 @@ Portfolio Wertentwicklung apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -3138,7 +3130,7 @@ Zeitstrahl der Dividenden apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -3146,7 +3138,7 @@ Suchst du nach einem Studentenrabatt? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3369,6 +3361,14 @@ 28 + + Everything in Basic, plus + Alles von Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satellit @@ -3422,7 +3422,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3438,7 +3438,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3454,7 +3454,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3470,7 +3470,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3518,7 +3518,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3602,7 +3602,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3618,7 +3618,7 @@ Einmalige Zahlung, keine automatische Erneuerung. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3638,7 +3638,7 @@ Es ist kostenlos. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3670,7 +3670,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3714,7 +3714,7 @@ E-Mail und Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3766,7 +3766,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3790,7 +3790,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4034,7 +4034,7 @@ Aktueller Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4042,7 +4042,7 @@ Längster Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4489,14 +4489,6 @@ 43 - - Everything in - Alles von - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs ohne Länder @@ -5396,7 +5388,7 @@ mit deiner Universitäts-E-Mail-Adresse apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5580,7 +5572,7 @@ Fordere ihn an apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5900,7 +5892,7 @@ hier apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5916,7 +5908,7 @@ Absolute Anlage Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5924,7 +5916,7 @@ Anlage Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5932,7 +5924,7 @@ Absolute Währungsperformance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5940,7 +5932,7 @@ Währungsperformance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6881,7 +6873,7 @@ Wenn du die Eröffnung eines Kontos planst bei apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6993,7 +6985,7 @@ um unseren Empfehlungslink zu verwenden und eine Ghostfolio Premium-Mitgliedschaft für ein Jahr zu erhalten apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7403,7 +7395,7 @@ Änderung mit Währungseffekt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7567,7 +7559,7 @@ Gesamtbetrag apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7748,7 +7740,7 @@ inklusive API-Zugriff für apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index a1b6e45e4..7564e4d80 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -40,10 +40,10 @@ please - please + por favor apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -84,20 +84,12 @@ with - with + con apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? ¿Quieres revocar el acceso concedido? @@ -376,7 +368,7 @@ and is driven by the efforts of its contributors - and is driven by the efforts of its contributors + y es impulsado por los esfuerzos de sus contribuidores apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -660,7 +652,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + No se renueva automáticamente la membresía. apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -727,7 +719,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -859,7 +851,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -911,7 +903,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -923,7 +915,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1104,10 +1096,10 @@ Performance with currency effect - Performance with currency effect + Rendimiento con el efecto del tipo de cambio de divisa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -1247,7 +1239,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1847,7 +1839,7 @@ Cronología de la inversión apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -1855,7 +1847,7 @@ Lo mejor apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -1863,7 +1855,7 @@ Lo peor apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -1920,7 +1912,7 @@ Current week - Current week + Semana actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 191 @@ -2084,7 +2076,7 @@ or start a discussion at - or start a discussion at + o iniciar una discusión en apps/client/src/app/pages/about/overview/about-overview-page.html 94 @@ -2156,7 +2148,7 @@ Sustainable retirement income - Sustainable retirement income + Ingreso sostenible de retiro apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -2328,10 +2320,10 @@ contact us - contact us + contactarnos apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2428,7 +2420,7 @@ Latest activities - Latest activities + Últimas actividades apps/client/src/app/pages/public/public-page.html 211 @@ -2544,7 +2536,7 @@ annual interest rate - annual interest rate + tasa de interés anual apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -2664,7 +2656,7 @@ Could not validate form - Could not validate form + No se pudo validar el formulario apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 554 @@ -2747,7 +2739,7 @@ Evolución cartera apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -2900,7 +2892,7 @@ Authentication - Authentication + Autenticación apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 35 @@ -3052,7 +3044,7 @@ If you retire today, you would be able to withdraw - If you retire today, you would be able to withdraw + Si te retirases hoy, podrías sacar apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -3120,10 +3112,10 @@ Looking for a student discount? - Looking for a student discount? + ¿Buscando un descuento para estudiantes? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3163,7 +3155,7 @@ Calendario de dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -3354,6 +3346,14 @@ 28 + + Everything in Basic, plus + Todo en Básico, más + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satélite @@ -3407,7 +3407,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3423,7 +3423,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3439,7 +3439,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3455,7 +3455,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3503,7 +3503,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3587,7 +3587,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3603,12 +3603,12 @@ Pago único, sin renovación automática. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 Could not save asset profile - Could not save asset profile + No se pudo guardar el perfil del activo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 588 @@ -3623,7 +3623,7 @@ Es gratis. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3655,7 +3655,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3699,7 +3699,7 @@ Soporte a Traves de Email y Chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3743,7 +3743,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3767,7 +3767,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3812,7 +3812,7 @@ By - By + Por apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -3828,7 +3828,7 @@ Current year - Current year + Año actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 199 @@ -3864,7 +3864,7 @@ Asset profile has been saved - Asset profile has been saved + El perfil del activo ha sido guardado apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 578 @@ -4011,7 +4011,7 @@ Racha actual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4019,7 +4019,7 @@ Racha más larga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4056,7 +4056,7 @@ View Details - View Details + Ver detalles apps/client/src/app/components/admin-users/admin-users.html 225 @@ -4192,7 +4192,7 @@ per week - per week + por semana apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 130 @@ -4216,7 +4216,7 @@ and we share aggregated key metrics of the platform’s performance - and we share aggregated key metrics of the platform’s performance + y compartimos agregados métricas clave del rendimiento de la plataforma apps/client/src/app/pages/about/overview/about-overview-page.html 32 @@ -4260,7 +4260,7 @@ Website of Thomas Kaul - Website of Thomas Kaul + Sitio web de Thomas Kaul apps/client/src/app/pages/about/overview/about-overview-page.html 44 @@ -4440,7 +4440,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + Iniciar sesión con OpenID Connect apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -4466,14 +4466,6 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs sin países @@ -4540,7 +4532,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - The source code is fully available as open source software (OSS) under the AGPL-3.0 license + El código fuente está disponible completamente en software de código abierto (OSS) bajo la licencia AGPL-3.0 apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -4612,7 +4604,7 @@ this is projected to increase to - this is projected to increase to + esto se proyecta a aumentar a apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -4664,7 +4656,7 @@ Job ID - Job ID + ID de trabajo apps/client/src/app/components/admin-jobs/admin-jobs.html 34 @@ -4748,7 +4740,7 @@ for - for + para apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 128 @@ -4772,7 +4764,7 @@ Could not parse scraper configuration - Could not parse scraper configuration + No se pudo analizar la configuración del scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 509 @@ -4816,7 +4808,7 @@ Edit access - Edit access + Editar acceso apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 11 @@ -4888,7 +4880,7 @@ Get access to 80’000+ tickers from over 50 exchanges - Get access to 80’000+ tickers from over 50 exchanges + Obtén acceso a más de 80,000 tickers de más de 50 exchanges apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 84 @@ -5072,7 +5064,7 @@ less than - less than + menos que apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 129 @@ -5362,7 +5354,7 @@ Ghostfolio Status - Ghostfolio Status + Estado de Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 62 @@ -5370,10 +5362,10 @@ with your university e-mail address - with your university e-mail address + con tu dirección de correo electrónico de la universidad apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5390,7 +5382,7 @@ and a safe withdrawal rate (SWR) of - and a safe withdrawal rate (SWR) of + y una tasa de retiro segura (SWR) de apps/client/src/app/pages/portfolio/fire/fire-page.html 108 @@ -5554,10 +5546,10 @@ Request it - Request it + Solicitar apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5610,7 +5602,7 @@ , - , + , apps/client/src/app/pages/portfolio/fire/fire-page.html 145 @@ -5626,7 +5618,7 @@ per month - per month + por mes apps/client/src/app/pages/portfolio/fire/fire-page.html 94 @@ -5874,15 +5866,15 @@ here - here + aquí apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 Close Holding - Close Holding + Cerrar posición apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 442 @@ -5893,7 +5885,7 @@ Rendimiento absoluto de los activos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5901,7 +5893,7 @@ Rendimiento de activos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5909,7 +5901,7 @@ Rendimiento absoluto de divisas apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5917,7 +5909,7 @@ Rendimiento de la moneda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6183,7 +6175,7 @@ {VAR_PLURAL, plural, =1 {activity} other {activities}} - {VAR_PLURAL, plural, =1 {activity} other {activities}} + {VAR_PLURAL, plural, =1 {actividad} other {actividades}} apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 14 @@ -6263,7 +6255,7 @@ Include in - Include in + Incluir en apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 374 @@ -6547,7 +6539,7 @@ View Holding - View Holding + Ver fondos libs/ui/src/lib/activities-table/activities-table.component.html 450 @@ -6691,7 +6683,7 @@ Oops! Could not update access. - Oops! Could not update access. + Oops! No se pudo actualizar el acceso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 178 @@ -6699,7 +6691,7 @@ , based on your total assets of - , based on your total assets of + , basado en tus activos totales de apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6771,7 +6763,7 @@ Close - Cerca + Cerrar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 594 @@ -6815,7 +6807,7 @@ Role - Role + Rol apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 14 @@ -6847,7 +6839,7 @@ Change with currency effect Change - Change with currency effect Change + Cambiar con efecto de cambio dedivisa Cambiar apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 63 @@ -6855,15 +6847,15 @@ If you plan to open an account at - If you plan to open an account at + Si planeas abrir una cuenta en apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 Performance with currency effect Performance - Performance with currency effect Performance + Rendimiento con cambio de divisa Rendimiento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 83 @@ -6887,7 +6879,7 @@ send an e-mail to - send an e-mail to + enviar un correo electrónico a apps/client/src/app/pages/about/overview/about-overview-page.html 87 @@ -6959,7 +6951,7 @@ , assuming a - , assuming a + , asumiendo un apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6967,10 +6959,10 @@ to use our referral link and get a Ghostfolio Premium membership for one year - to use our referral link and get a Ghostfolio Premium membership for one year + para usar nuestro enlace de referido y obtener una membresía Ghostfolio Premium por un año apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7047,7 +7039,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio es una aplicación de gestión de patrimonio para aquellos individuos que desean realizar un seguimiento de acciones, ETFs o criptomonedas y tomar decisiones de inversión sólidas y basadas en datos. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7361,7 +7353,7 @@ Check the system status at - Check the system status at + Verificar el estado del sistema en apps/client/src/app/pages/about/overview/about-overview-page.html 57 @@ -7377,10 +7369,10 @@ Change with currency effect - Change with currency effect + Cambiar con el efecto del tipo de cambio de divisa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7517,7 +7509,7 @@ The project has been initiated by - The project has been initiated by + El proyecto ha sido iniciado por apps/client/src/app/pages/about/overview/about-overview-page.html 40 @@ -7541,10 +7533,10 @@ Total amount - Total amount + Cantidad total apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7633,7 +7625,7 @@ Find account, holding or page... - Find account, holding or page... + Buscar cuenta, posición o página... libs/ui/src/lib/assistant/assistant.component.ts 151 @@ -7725,7 +7717,7 @@ con acceso a la API para apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8024,7 +8016,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8036,7 +8028,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8057,7 +8049,7 @@ Current month - Current month + Mes actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 195 @@ -8242,7 +8234,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ + Si encuentras un error, deseas sugerir una mejora o una nueva característica, por favor únete a la comunidad Ghostfolio Slack, publica en @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 69 @@ -8274,7 +8266,7 @@ - + apps/client/src/app/components/admin-users/admin-users.html 39 @@ -8342,7 +8334,7 @@ Economic Market Cluster Risks - Economic Market Cluster Risks + Riesgos del clúster de mercados económicos apps/client/src/app/pages/i18n/i18n-page.html 106 @@ -8350,7 +8342,7 @@ Emergency Fund - Emergency Fund + Fondo de emergencia apps/client/src/app/pages/i18n/i18n-page.html 144 @@ -8358,7 +8350,7 @@ Fees - Fees + Comisiones apps/client/src/app/pages/i18n/i18n-page.html 161 @@ -8366,7 +8358,7 @@ Liquidity - Liquidity + Liquidez apps/client/src/app/pages/i18n/i18n-page.html 70 @@ -8374,7 +8366,7 @@ Buying Power - Buying Power + Poder de compra apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8382,7 +8374,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Your buying power is below ${thresholdMin} ${baseCurrency} + Tu poder de compra es inferior a ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8390,7 +8382,7 @@ Your buying power is 0 ${baseCurrency} - Your buying power is 0 ${baseCurrency} + Tu poder de compra es 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8398,7 +8390,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Tu poder de compra excede ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8430,7 +8422,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% + La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 112 @@ -8438,7 +8430,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% + La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 117 @@ -8446,7 +8438,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 122 @@ -8462,7 +8454,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 130 @@ -8470,7 +8462,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% + La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 135 @@ -8478,7 +8470,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 140 @@ -8502,7 +8494,7 @@ Asia-Pacific - Asia-Pacific + Asia-Pacífico apps/client/src/app/pages/i18n/i18n-page.html 165 @@ -8510,7 +8502,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 167 @@ -8518,7 +8510,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 171 @@ -8526,7 +8518,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 175 @@ -8534,7 +8526,7 @@ Emerging Markets - Emerging Markets + Mercados emergentes apps/client/src/app/pages/i18n/i18n-page.html 180 @@ -8542,7 +8534,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 183 @@ -8550,7 +8542,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 187 @@ -8558,7 +8550,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 191 @@ -8566,7 +8558,7 @@ Europe - Europe + Europa apps/client/src/app/pages/i18n/i18n-page.html 195 @@ -8574,7 +8566,7 @@ The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 197 @@ -8582,7 +8574,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 201 @@ -8590,7 +8582,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 205 @@ -8702,7 +8694,7 @@ Registration Date - Registration Date + Fecha de registro apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 26 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 05dc0f7e3..0da1c3f6a 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -34,7 +34,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -81,14 +81,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Voulez-vous vraiment révoquer cet accès ? @@ -1142,7 +1134,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1194,7 +1186,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1206,7 +1198,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1354,7 +1346,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -1542,7 +1534,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2394,7 +2386,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -2458,7 +2450,7 @@ Haut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -2466,7 +2458,7 @@ Bas apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -2474,7 +2466,7 @@ Évolution du Portefeuille apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -2482,7 +2474,7 @@ Historique des Investissements apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -2490,7 +2482,7 @@ Historique des Dividendes apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -2594,7 +2586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -2822,7 +2814,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -3353,6 +3345,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satellite @@ -3406,7 +3406,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3422,7 +3422,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3438,7 +3438,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3454,7 +3454,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3502,7 +3502,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3586,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3602,7 +3602,7 @@ Paiement unique, sans auto-renouvellement. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3622,7 +3622,7 @@ C’est gratuit. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3654,7 +3654,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3698,7 +3698,7 @@ Support par E-mail et Tchat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3742,7 +3742,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3766,7 +3766,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4010,7 +4010,7 @@ Série en cours apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4018,7 +4018,7 @@ Série la plus longue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4465,14 +4465,6 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF sans Pays @@ -5372,7 +5364,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5556,7 +5548,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5876,7 +5868,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5892,7 +5884,7 @@ Performance des Actifs en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5900,7 +5892,7 @@ Performance des Actifs apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5908,7 +5900,7 @@ Performance des devises en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5916,7 +5908,7 @@ Performance des devises apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6857,7 +6849,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6969,7 +6961,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7379,7 +7371,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ avec accès API pour apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 26545f435..746e1fbd1 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -43,7 +43,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -90,14 +90,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Vuoi davvero revocare l’accesso concesso? @@ -727,7 +719,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -859,7 +851,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -911,7 +903,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -923,7 +915,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1107,7 +1099,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -1247,7 +1239,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1847,7 +1839,7 @@ Cronologia degli investimenti apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -1855,7 +1847,7 @@ In alto apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -1863,7 +1855,7 @@ In basso apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -2331,7 +2323,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2747,7 +2739,7 @@ Evoluzione del portafoglio apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -3123,7 +3115,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3163,7 +3155,7 @@ Cronologia dei dividendi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -3354,6 +3346,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satellite @@ -3407,7 +3407,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3423,7 +3423,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3439,7 +3439,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3455,7 +3455,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3503,7 +3503,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3587,7 +3587,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3603,7 +3603,7 @@ Pagamento una tantum, senza rinnovo automatico. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3623,7 +3623,7 @@ È gratuito. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3655,7 +3655,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3699,7 +3699,7 @@ Supporto via email e chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3743,7 +3743,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3767,7 +3767,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4011,7 +4011,7 @@ Serie attuale apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4019,7 +4019,7 @@ Serie più lunga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4466,14 +4466,6 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF senza paesi @@ -5373,7 +5365,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5557,7 +5549,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5877,7 +5869,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5893,7 +5885,7 @@ Rendimento assoluto dell’Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5901,7 +5893,7 @@ Rendimento dell’Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5909,7 +5901,7 @@ Rendimento assoluto della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5917,7 +5909,7 @@ Rendimento della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6858,7 +6850,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6970,7 +6962,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7380,7 +7372,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7544,7 +7536,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7725,7 +7717,7 @@ con accesso API per apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8024,7 +8016,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8036,7 +8028,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.ko.xlf b/apps/client/src/locales/messages.ko.xlf index 05f02c87b..67443706b 100644 --- a/apps/client/src/locales/messages.ko.xlf +++ b/apps/client/src/locales/messages.ko.xlf @@ -244,7 +244,7 @@ 부탁드립니다 apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -291,14 +291,6 @@ 87 - - plus - 추가로 - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? 이 부여된 접근 권한을 정말로 회수하시겠습니까? @@ -767,14 +759,6 @@ 96 - - Everything in - 다음 통화 기준으로 모두 표시 - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries 국가 정보 없는 ETF @@ -1776,7 +1760,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1840,7 +1824,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1852,7 +1836,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1996,7 +1980,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -2016,7 +2000,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2032,7 +2016,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2048,7 +2032,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2060,7 +2044,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2076,7 +2060,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2132,7 +2116,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2188,7 +2172,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2276,7 +2260,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -3116,7 +3100,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -3572,7 +3556,7 @@ 대학 이메일 주소로 apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4124,7 +4108,7 @@ 학생 할인을 찾고 계십니까? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4196,7 +4180,7 @@ 상위 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -4204,7 +4188,7 @@ 하위 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -4212,7 +4196,7 @@ 포트폴리오 진화 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -4220,7 +4204,7 @@ 투자 일정 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -4228,7 +4212,7 @@ 현재 연속 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4236,7 +4220,7 @@ 최장 연속 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4244,7 +4228,7 @@ 배당 일정 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -4420,7 +4404,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4436,7 +4420,7 @@ 이메일 및 채팅 지원 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4452,7 +4436,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4460,7 +4444,7 @@ 일회성 결제, 자동 갱신 없음. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -4480,7 +4464,7 @@ 무료입니다. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4901,7 +4885,7 @@ 요청하세요 apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5069,7 +5053,7 @@ 저희에게 연락주세요 apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5396,6 +5380,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite 위성 @@ -5877,7 +5869,7 @@ 절대적인 통화 성과 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5893,7 +5885,7 @@ 절대자산성과 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5925,7 +5917,7 @@ 여기 apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5933,7 +5925,7 @@ 자산 성과 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5941,7 +5933,7 @@ 통화 성과 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6898,7 +6890,7 @@ 에서 계좌를 개설할 계획이라면 apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6986,7 +6978,7 @@ 추천 링크를 사용하고 1년 동안 Ghostfolio 프리미엄 멤버십을 얻으려면 apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7404,7 +7396,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7568,7 +7560,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7749,7 +7741,7 @@ 다음에 대한 API 액세스 권한이 있는 apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8024,7 +8016,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8036,7 +8028,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 773937956..d7d0b71e8 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -42,7 +42,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -89,14 +89,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Wil je deze verleende toegang echt intrekken? @@ -726,7 +718,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -858,7 +850,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -910,7 +902,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -922,7 +914,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1106,7 +1098,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -1246,7 +1238,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1846,7 +1838,7 @@ Tijdlijn investeringen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -1854,7 +1846,7 @@ Winnaars apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -1862,7 +1854,7 @@ Verliezers apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -2330,7 +2322,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2746,7 +2738,7 @@ Waardeontwikkeling van portefeuille apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -3122,7 +3114,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3162,7 +3154,7 @@ Tijdlijn dividend apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -3353,6 +3345,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satelliet @@ -3406,7 +3406,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3422,7 +3422,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3438,7 +3438,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3454,7 +3454,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3502,7 +3502,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3586,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3602,7 +3602,7 @@ Eenmalige betaling, geen automatische verlenging. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3622,7 +3622,7 @@ Het is gratis. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3654,7 +3654,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3698,7 +3698,7 @@ Ondersteuning via e-mail en chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3742,7 +3742,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3766,7 +3766,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4010,7 +4010,7 @@ Huidige reeks apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4018,7 +4018,7 @@ Langste reeks apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4465,14 +4465,6 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF’s zonder Landen @@ -5372,7 +5364,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5556,7 +5548,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5876,7 +5868,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5892,7 +5884,7 @@ Absolute Activaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5900,7 +5892,7 @@ Activaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5908,7 +5900,7 @@ Absolute Valutaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5916,7 +5908,7 @@ Valutaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6857,7 +6849,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6969,7 +6961,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7379,7 +7371,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ met API toegang tot apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index f4d14b81e..a94a76d2f 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -243,7 +243,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -290,14 +290,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Czy na pewno chcesz cofnąć przyznany dostęp? @@ -758,14 +750,6 @@ 96 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF-y bez Krajów @@ -1743,7 +1727,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1807,7 +1791,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1819,7 +1803,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1963,7 +1947,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1983,7 +1967,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -1999,7 +1983,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2015,7 +1999,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2027,7 +2011,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2043,7 +2027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2099,7 +2083,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2155,7 +2139,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2243,7 +2227,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -3083,7 +3067,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -3539,7 +3523,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4091,7 +4075,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4163,7 +4147,7 @@ Największe wzrosty apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -4171,7 +4155,7 @@ Największy spadek apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -4179,7 +4163,7 @@ Rozwój portfela apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -4187,7 +4171,7 @@ Oś czasu inwestycji apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -4195,7 +4179,7 @@ Obecna passa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4203,7 +4187,7 @@ Najdłuższa passa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4211,7 +4195,7 @@ Oś czasu dywidend apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -4387,7 +4371,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4403,7 +4387,7 @@ Wsparcie przez E-mail i Czat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4419,7 +4403,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4427,7 +4411,7 @@ Płatność jednorazowa, bez automatycznego odnawiania. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -4447,7 +4431,7 @@ Jest bezpłatny. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4856,7 +4840,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5000,7 +4984,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5327,6 +5311,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satelita @@ -5876,7 +5868,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5892,7 +5884,7 @@ Łączny wynik aktywów apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5900,7 +5892,7 @@ Wyniki aktywów apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5908,7 +5900,7 @@ Łączny wynik walut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5916,7 +5908,7 @@ Wynik walut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6857,7 +6849,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6969,7 +6961,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7379,7 +7371,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ z dostępem API dla apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 1e92933dc..2bcd7c401 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -34,7 +34,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -81,14 +81,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Pretende realmente revogar este acesso concedido? @@ -1026,7 +1018,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1078,7 +1070,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1090,7 +1082,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1350,7 +1342,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -1538,7 +1530,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2374,7 +2366,7 @@ Topo apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -2382,7 +2374,7 @@ Fundo apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -2390,7 +2382,7 @@ Evolução do Portefólio apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -2398,7 +2390,7 @@ Cronograma de Investimento apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -2530,7 +2522,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -2722,7 +2714,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -3186,7 +3178,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3226,7 +3218,7 @@ Cronograma de Dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -3353,6 +3345,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satélite @@ -3406,7 +3406,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3422,7 +3422,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3438,7 +3438,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3454,7 +3454,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3502,7 +3502,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3586,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3602,7 +3602,7 @@ Pagamento único, sem renovação automática. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3622,7 +3622,7 @@ É gratuito. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3654,7 +3654,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3698,7 +3698,7 @@ Suporte por Email e Chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3742,7 +3742,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3766,7 +3766,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4010,7 +4010,7 @@ Série Atual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4018,7 +4018,7 @@ Série mais Longa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4465,14 +4465,6 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs sem países @@ -5372,7 +5364,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5556,7 +5548,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5876,7 +5868,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5892,7 +5884,7 @@ Desempenho absoluto de ativos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5900,7 +5892,7 @@ Desempenho de ativos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5908,7 +5900,7 @@ Desempenho absoluto da moeda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5916,7 +5908,7 @@ Desempenho da moeda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6857,7 +6849,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6969,7 +6961,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7379,7 +7371,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index cdbfaec8f..421ef3855 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -215,7 +215,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -262,14 +262,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Bu erişim iznini geri almayı gerçekten istiyor musunuz? @@ -722,14 +714,6 @@ 96 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries Ülkesi Olmayan ETF’ler @@ -1611,7 +1595,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1663,7 +1647,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1675,7 +1659,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1831,7 +1815,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1851,7 +1835,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -1867,7 +1851,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -1883,7 +1867,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -1895,7 +1879,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -1911,7 +1895,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -1967,7 +1951,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2023,7 +2007,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2659,7 +2643,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -3575,7 +3559,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3647,7 +3631,7 @@ Üst apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -3655,7 +3639,7 @@ Alt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -3663,7 +3647,7 @@ Portföyün Gelişimi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -3671,7 +3655,7 @@ Yatırım Zaman Çizelgesi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -3679,7 +3663,7 @@ Güncel Seri apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -3687,7 +3671,7 @@ En Uzun Seri apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -3695,7 +3679,7 @@ Temettü Zaman Çizelgesi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -3871,7 +3855,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3887,7 +3871,7 @@ E-posta ve Sohbet Desteği apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3903,7 +3887,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3911,7 +3895,7 @@ Tek seferlik ödeme, otomatik yenileme yok. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3931,7 +3915,7 @@ Ücretsiz. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4428,7 +4412,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -4696,7 +4680,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5023,6 +5007,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Uydu @@ -5380,7 +5372,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5556,7 +5548,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5876,7 +5868,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5892,7 +5884,7 @@ Mutlak Varlık Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5900,7 +5892,7 @@ Varlık Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5908,7 +5900,7 @@ Mutlak Para Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5916,7 +5908,7 @@ Para Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6857,7 +6849,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6969,7 +6961,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7379,7 +7371,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ API erişimi için apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index a7d0d1ca3..2fc389030 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -295,7 +295,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -374,14 +374,6 @@ 99 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Ви дійсно хочете відкликати цей наданий доступ? @@ -858,14 +850,6 @@ 96 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF без країн @@ -1551,7 +1535,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1771,7 +1755,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -1787,7 +1771,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -1831,7 +1815,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -2215,7 +2199,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -2227,7 +2211,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -2439,7 +2423,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -2459,7 +2443,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2475,7 +2459,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2491,7 +2475,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2503,7 +2487,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2519,7 +2503,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2611,7 +2595,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2815,7 +2799,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -3728,7 +3712,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -4200,7 +4184,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4796,7 +4780,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4860,7 +4844,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -4892,7 +4876,7 @@ Абсолютна прибутковість активів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -4900,7 +4884,7 @@ Прибутковість активів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -4908,7 +4892,7 @@ Абсолютна прибутковість валюти apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -4916,7 +4900,7 @@ Прибутковість валюти apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -4924,7 +4908,7 @@ Топ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -4932,7 +4916,7 @@ Низ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -4940,7 +4924,7 @@ Еволюція портфеля apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -4948,7 +4932,7 @@ Інвестиційний графік apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -4956,7 +4940,7 @@ Поточна серія apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4964,7 +4948,7 @@ Найдовша серія apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4972,7 +4956,7 @@ Графік дивідендів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -5188,7 +5172,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -5204,7 +5188,7 @@ Підтримка електронної пошти та чату apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -5212,7 +5196,7 @@ Разова оплата, без автоматичного поновлення. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -5232,7 +5216,7 @@ Це безкоштовно. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -5847,7 +5831,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -6035,7 +6019,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -6323,7 +6307,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -6790,6 +6774,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Супутник @@ -7387,7 +7379,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7543,7 +7535,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7724,7 +7716,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8023,7 +8015,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8035,7 +8027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index f339f807e..a6907698d 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -228,7 +228,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -271,13 +271,6 @@ 87 - - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? @@ -718,13 +711,6 @@ 96 - - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries @@ -1631,7 +1617,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1689,7 +1675,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1700,7 +1686,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1829,7 +1815,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1848,7 +1834,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -1863,7 +1849,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -1878,7 +1864,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -1889,7 +1875,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -1904,7 +1890,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -1957,7 +1943,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2008,7 +1994,7 @@ Performance with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2087,7 +2073,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2860,7 +2846,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -3104,6 +3090,13 @@ 172 + + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + trading stocks, ETFs or cryptocurrencies on multiple platforms @@ -3269,7 +3262,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -3766,7 +3759,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3832,49 +3825,49 @@ Top apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 Bottom apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 Portfolio Evolution apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 Investment Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 Current Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 Longest Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 Dividend Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -4034,7 +4027,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4048,7 +4041,7 @@ Email and Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4063,14 +4056,14 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 One-time payment, no auto-renewal. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -4088,7 +4081,7 @@ It’s free. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4470,7 +4463,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -4619,7 +4612,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5348,7 +5341,7 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5362,7 +5355,7 @@ Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5392,21 +5385,21 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6267,7 +6260,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6345,7 +6338,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -6723,7 +6716,7 @@ Change with currency effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -6869,7 +6862,7 @@ Total amount apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7029,7 +7022,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7275,7 +7268,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -7286,7 +7279,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index c941fa2f2..7ec9d85a0 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -244,7 +244,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -291,14 +291,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? 您真的要撤销此访问权限吗? @@ -767,14 +759,6 @@ 96 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries 没有国家的 ETF @@ -1229,7 +1213,7 @@ Asset profile has been saved - Asset profile has been saved + 资产概况已保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 578 @@ -1245,7 +1229,7 @@ By - By + 预计到 apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -1357,7 +1341,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + 会员资格不自动续订。 apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -1401,7 +1385,7 @@ Could not validate form - Could not validate form + 无法验证表单 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 554 @@ -1752,7 +1736,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1816,7 +1800,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 257 + 259 @@ -1828,7 +1812,7 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 276 + 278 @@ -1972,7 +1956,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1992,7 +1976,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2008,7 +1992,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2024,7 +2008,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2036,7 +2020,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2052,7 +2036,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2108,7 +2092,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2161,10 +2145,10 @@ Performance with currency effect - Performance with currency effect + 含货币影响的表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 134 + 135 @@ -2252,7 +2236,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2389,7 +2373,7 @@ this is projected to increase to - this is projected to increase to + 预计将增至 apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -2901,7 +2885,7 @@ Could not parse scraper configuration - Could not parse scraper configuration + 无法解析抓取器配置 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 509 @@ -3092,7 +3076,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html @@ -3359,6 +3343,14 @@ 172 + + Everything in Basic, plus + 包含 Basic 所有功能,以及 + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + trading stocks, ETFs or cryptocurrencies on multiple platforms 在多个平台上交易股票、ETF 或加密货币 @@ -3548,7 +3540,7 @@ 使用您的学校电子邮件地址 apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4100,7 +4092,7 @@ 寻找学生折扣? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4137,7 +4129,7 @@ annual interest rate - annual interest rate + 年利率 apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -4172,7 +4164,7 @@ 顶部 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 303 + 305 @@ -4180,7 +4172,7 @@ 底部 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 352 + 354 @@ -4188,7 +4180,7 @@ 投资组合演变 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 405 + 407 @@ -4196,7 +4188,7 @@ 投资时间表 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 432 + 434 @@ -4204,7 +4196,7 @@ 当前连胜 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 453 + 455 @@ -4212,7 +4204,7 @@ 最长连续纪录 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 462 + 464 @@ -4220,7 +4212,7 @@ 股息时间表 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 489 + 491 @@ -4369,7 +4361,7 @@ Free - 自由的 + 免费 apps/client/src/app/pages/pricing/pricing-page.html 86 @@ -4396,7 +4388,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4412,7 +4404,7 @@ 电子邮件和聊天支持 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4428,7 +4420,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4436,12 +4428,12 @@ 一次性付款,无自动续订。 apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 Could not save asset profile - Could not save asset profile + 无法保存资产概况 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 588 @@ -4456,7 +4448,7 @@ 免费。 apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4877,7 +4869,7 @@ 请求它 apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5045,7 +5037,7 @@ 联系我们 apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5450,7 +5442,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + 使用 OpenID Connect 登录 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -5562,7 +5554,7 @@ Authentication - Authentication + 认证 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 35 @@ -5853,7 +5845,7 @@ 绝对货币表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 209 + 211 @@ -5869,7 +5861,7 @@ 绝对资产回报 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 166 + 168 @@ -5901,7 +5893,7 @@ 这里 apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5909,7 +5901,7 @@ 资产回报 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 188 + 190 @@ -5917,7 +5909,7 @@ 货币表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 234 + 236 @@ -6699,7 +6691,7 @@ , based on your total assets of - 基于您总资产的 + 基于您总资产的 apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6858,7 +6850,7 @@ 如果您计划开通账户在 apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6959,7 +6951,7 @@ , assuming a - , assuming a + , 假设一个 apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6970,7 +6962,7 @@ 使用我们的推荐链接并获得一年的Ghostfolio Premium会员资格 apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7377,10 +7369,10 @@ Change with currency effect - Change with currency effect + 含货币影响的涨跌 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 115 + 116 @@ -7541,10 +7533,10 @@ Total amount - Total amount + 总金额 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 94 + 95 @@ -7725,7 +7717,7 @@ 包含 API 访问权限,适用于 apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -8024,7 +8016,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8036,7 +8028,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 diff --git a/libs/common/eslint.config.cjs b/libs/common/eslint.config.cjs index a78dde897..990c264b4 100644 --- a/libs/common/eslint.config.cjs +++ b/libs/common/eslint.config.cjs @@ -18,7 +18,9 @@ module.exports = [ { files: ['**/*.ts', '**/*.tsx'], // Override or add rules here - rules: {} + rules: { + '@typescript-eslint/prefer-nullish-coalescing': 'error' + } }, { files: ['**/*.js', '**/*.jsx'], diff --git a/libs/common/src/lib/chart-helper.ts b/libs/common/src/lib/chart-helper.ts index 697f39467..1f385e901 100644 --- a/libs/common/src/lib/chart-helper.ts +++ b/libs/common/src/lib/chart-helper.ts @@ -1,4 +1,13 @@ -import { Chart, TooltipPosition } from 'chart.js'; +import type { ElementRef } from '@angular/core'; +import type { + Chart, + ChartType, + ControllerDatasetOptions, + Plugin, + Point, + TooltipOptions, + TooltipPosition +} from 'chart.js'; import { format } from 'date-fns'; import { @@ -15,7 +24,7 @@ export function formatGroupedDate({ date, groupBy }: { - date: Date; + date: number; groupBy: GroupBy; }) { if (groupBy === 'month') { @@ -27,47 +36,55 @@ export function formatGroupedDate({ return format(date, DATE_FORMAT); } -export function getTooltipOptions({ +export function getTooltipOptions({ colorScheme, currency = '', groupBy, locale = getLocale(), unit = '' }: { - colorScheme?: ColorScheme; + colorScheme: ColorScheme; currency?: string; groupBy?: GroupBy; locale?: string; unit?: string; -} = {}) { +}): Partial> { return { backgroundColor: getBackgroundColor(colorScheme), bodyColor: `rgb(${getTextColor(colorScheme)})`, borderWidth: 1, borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`, + // @ts-expect-error: no need to set all attributes in callbacks callbacks: { label: (context) => { - let label = context.dataset.label || ''; + let label = (context.dataset as ControllerDatasetOptions).label ?? ''; + if (label) { label += ': '; } - if (context.parsed.y !== null) { + + const yPoint = (context.parsed as Point).y; + + if (yPoint !== null) { if (currency) { - label += `${context.parsed.y.toLocaleString(locale, { + label += `${yPoint.toLocaleString(locale, { maximumFractionDigits: 2, minimumFractionDigits: 2 })} ${currency}`; } else if (unit) { - label += `${context.parsed.y.toFixed(2)} ${unit}`; + label += `${yPoint.toFixed(2)} ${unit}`; } else { - label += context.parsed.y.toFixed(2); + label += yPoint.toFixed(2); } } + return label; }, title: (contexts) => { - if (groupBy) { - return formatGroupedDate({ groupBy, date: contexts[0].parsed.x }); + const xPoint = (contexts[0].parsed as Point).x; + + if (groupBy && xPoint !== null) { + return formatGroupedDate({ groupBy, date: xPoint }); } return contexts[0].label; @@ -92,16 +109,17 @@ export function getTooltipPositionerMapTop( if (!position || !chart?.chartArea) { return false; } + return { x: position.x, y: chart.chartArea.top }; } -export function getVerticalHoverLinePlugin( - chartCanvas, - colorScheme?: ColorScheme -) { +export function getVerticalHoverLinePlugin( + chartCanvas: ElementRef, + colorScheme: ColorScheme +): Plugin { return { afterDatasetsDraw: (chart, _, options) => { const active = chart.getActiveElements(); @@ -110,8 +128,8 @@ export function getVerticalHoverLinePlugin( return; } - const color = options.color || `rgb(${getTextColor(colorScheme)})`; - const width = options.width || 1; + const color = options.color ?? `rgb(${getTextColor(colorScheme)})`; + const width = options.width ?? 1; const { chartArea: { bottom, top } @@ -119,13 +137,16 @@ export function getVerticalHoverLinePlugin( const xValue = active[0].element.x; const context = chartCanvas.nativeElement.getContext('2d'); - context.lineWidth = width; - context.strokeStyle = color; - context.beginPath(); - context.moveTo(xValue, top); - context.lineTo(xValue, bottom); - context.stroke(); + if (context) { + context.lineWidth = width; + context.strokeStyle = color; + + context.beginPath(); + context.moveTo(xValue, top); + context.lineTo(xValue, bottom); + context.stroke(); + } }, id: 'verticalHoverLine' }; diff --git a/libs/common/src/lib/class-transformer.ts b/libs/common/src/lib/class-transformer.ts index 328e2bf9e..60e0eab60 100644 --- a/libs/common/src/lib/class-transformer.ts +++ b/libs/common/src/lib/class-transformer.ts @@ -16,7 +16,7 @@ export function transformToMapOfBig({ return mapOfBig; } -export function transformToBig({ value }: { value: string }): Big { +export function transformToBig({ value }: { value: string }): Big | null { if (value === null) { return null; } diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index a10a828e1..b558ccc42 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -78,6 +78,58 @@ export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000; +export const DEFAULT_REDACTED_PATHS = [ + 'accounts[*].balance', + 'accounts[*].valueInBaseCurrency', + 'activities[*].account.balance', + 'activities[*].account.comment', + 'activities[*].comment', + 'activities[*].fee', + 'activities[*].feeInAssetProfileCurrency', + 'activities[*].feeInBaseCurrency', + 'activities[*].quantity', + 'activities[*].SymbolProfile.symbolMapping', + 'activities[*].SymbolProfile.watchedByCount', + 'activities[*].value', + 'activities[*].valueInBaseCurrency', + 'balance', + 'balanceInBaseCurrency', + 'balances[*].account.balance', + 'balances[*].account.comment', + 'balances[*].value', + 'balances[*].valueInBaseCurrency', + 'comment', + 'dividendInBaseCurrency', + 'feeInBaseCurrency', + 'grossPerformance', + 'grossPerformanceWithCurrencyEffect', + 'historicalData[*].quantity', + 'holdings[*].dividend', + 'holdings[*].grossPerformance', + 'holdings[*].grossPerformanceWithCurrencyEffect', + 'holdings[*].holdings[*].valueInBaseCurrency', + 'holdings[*].investment', + 'holdings[*].netPerformance', + 'holdings[*].netPerformanceWithCurrencyEffect', + 'holdings[*].quantity', + 'holdings[*].valueInBaseCurrency', + 'interestInBaseCurrency', + 'investmentInBaseCurrencyWithCurrencyEffect', + 'netPerformance', + 'netPerformanceWithCurrencyEffect', + 'platforms[*].balance', + 'platforms[*].valueInBaseCurrency', + 'quantity', + 'SymbolProfile.symbolMapping', + 'SymbolProfile.watchedByCount', + 'totalBalanceInBaseCurrency', + 'totalDividendInBaseCurrency', + 'totalInterestInBaseCurrency', + 'totalValueInBaseCurrency', + 'value', + 'valueInBaseCurrency' +]; + // USX is handled separately export const DERIVED_CURRENCIES = [ { diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index cb4c0e1b7..4db1fcf2d 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -144,7 +144,7 @@ export function extractNumberFromString({ }: { locale?: string; value: string; -}): number { +}): number | undefined { try { // Remove non-numeric characters (excluding international formatting characters) const numericValue = value.replace(/[^\d.,'’\s]/g, ''); @@ -223,8 +223,8 @@ export function getDateFormatString(aLocale?: string) { ); return formatObject - .map((object) => { - switch (object.type) { + .map(({ type, value }) => { + switch (type) { case 'day': return 'dd'; case 'month': @@ -232,7 +232,7 @@ export function getDateFormatString(aLocale?: string) { case 'year': return 'yyyy'; default: - return object.value; + return value; } }) .join(''); @@ -271,9 +271,9 @@ export function getLowercase(object: object, path: string) { export function getNumberFormatDecimal(aLocale?: string) { const formatObject = new Intl.NumberFormat(aLocale).formatToParts(9999.99); - return formatObject.find((object) => { - return object.type === 'decimal'; - }).value; + return formatObject.find(({ type }) => { + return type === 'decimal'; + })?.value; } export function getNumberFormatGroup(aLocale = getLocale()) { @@ -281,9 +281,9 @@ export function getNumberFormatGroup(aLocale = getLocale()) { useGrouping: true }).formatToParts(9999.99); - return formatObject.find((object) => { - return object.type === 'group'; - }).value; + return formatObject.find(({ type }) => { + return type === 'group'; + })?.value; } export function getStartOfUtcDate(aDate: Date) { @@ -394,7 +394,7 @@ export function isRootCurrency(aCurrency: string) { }); } -export function parseDate(date: string): Date { +export function parseDate(date: string): Date | undefined { if (!date) { return undefined; } diff --git a/libs/common/src/lib/interfaces/admin-data.interface.ts b/libs/common/src/lib/interfaces/admin-data.interface.ts index 23821a86b..dd25b516d 100644 --- a/libs/common/src/lib/interfaces/admin-data.interface.ts +++ b/libs/common/src/lib/interfaces/admin-data.interface.ts @@ -1,12 +1,12 @@ import { DataProviderInfo } from './data-provider-info.interface'; export interface AdminData { + activitiesCount: number; dataProviders: (DataProviderInfo & { assetProfileCount: number; useForExchangeRates: boolean; })[]; settings: { [key: string]: boolean | object | string | string[] }; - transactionCount: number; userCount: number; version: string; } diff --git a/libs/common/src/lib/interfaces/portfolio-position.interface.ts b/libs/common/src/lib/interfaces/portfolio-position.interface.ts index 67a2f3e77..620cc00e9 100644 --- a/libs/common/src/lib/interfaces/portfolio-position.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-position.interface.ts @@ -39,10 +39,6 @@ export interface PortfolioPosition { sectors: Sector[]; symbol: string; tags?: Tag[]; - - /** @deprecated use activitiesCount instead */ - transactionCount: number; - type?: string; url?: string; valueInBaseCurrency?: number; diff --git a/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts b/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts index 1891b9cbb..90f1303e0 100644 --- a/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts @@ -7,7 +7,4 @@ export interface AccountsResponse { totalDividendInBaseCurrency: number; totalInterestInBaseCurrency: number; totalValueInBaseCurrency: number; - - /** @deprecated use activitiesCount instead */ - transactionCount: number; } diff --git a/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts b/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts index 1222ac6e9..8ac1a8279 100644 --- a/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts @@ -1,6 +1,3 @@ export interface CreateStripeCheckoutSessionResponse { - /** @deprecated */ - sessionId: string; - sessionUrl: string; } diff --git a/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts index cb06800be..4a087ad16 100644 --- a/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts @@ -39,7 +39,7 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 { })[]; markets: { [key in Market]: Pick< - PortfolioDetails['markets'][key], + NonNullable[key], 'id' | 'valueInPercentage' >; }; diff --git a/libs/common/src/lib/models/timeline-position.ts b/libs/common/src/lib/models/timeline-position.ts index 244d6595e..13f9001d5 100644 --- a/libs/common/src/lib/models/timeline-position.ts +++ b/libs/common/src/lib/models/timeline-position.ts @@ -35,9 +35,6 @@ export class TimelinePosition { @Type(() => Big) feeInBaseCurrency: Big; - /** @deprecated use dateOfFirstActivity instead */ - firstBuyDate: string; - @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) grossPerformance: Big; @@ -96,9 +93,6 @@ export class TimelinePosition { @Type(() => Big) timeWeightedInvestmentWithCurrencyEffect: Big; - /** @deprecated use activitiesCount instead */ - transactionCount: number; - @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) valueInBaseCurrency: Big; diff --git a/libs/common/src/lib/routes/interfaces/internal-route.interface.ts b/libs/common/src/lib/routes/interfaces/internal-route.interface.ts index 02f205979..f08cf8b5c 100644 --- a/libs/common/src/lib/routes/interfaces/internal-route.interface.ts +++ b/libs/common/src/lib/routes/interfaces/internal-route.interface.ts @@ -2,7 +2,7 @@ import { User } from '@ghostfolio/common/interfaces'; export interface InternalRoute { excludeFromAssistant?: boolean | ((aUser: User) => boolean); - path: string; + path?: string; routerLink: string[]; subRoutes?: Record; title: string; diff --git a/libs/common/src/lib/types/account-with-value.type.ts b/libs/common/src/lib/types/account-with-value.type.ts index 7f5fe79ba..23cb14749 100644 --- a/libs/common/src/lib/types/account-with-value.type.ts +++ b/libs/common/src/lib/types/account-with-value.type.ts @@ -7,10 +7,6 @@ export type AccountWithValue = AccountModel & { dividendInBaseCurrency: number; interestInBaseCurrency: number; platform?: Platform; - - /** @deprecated use activitiesCount instead */ - transactionCount: number; - value: number; valueInBaseCurrency: number; }; diff --git a/libs/common/src/lib/utils/form.util.ts b/libs/common/src/lib/utils/form.util.ts index 425aa4699..b510e6215 100644 --- a/libs/common/src/lib/utils/form.util.ts +++ b/libs/common/src/lib/utils/form.util.ts @@ -29,7 +29,7 @@ export async function validateObjectForForm({ if (formControl) { formControl.setErrors({ - validationError: Object.values(constraints)[0] + validationError: Object.values(constraints ?? {})[0] }); } @@ -37,7 +37,7 @@ export async function validateObjectForForm({ if (formControlInCustomCurrency) { formControlInCustomCurrency.setErrors({ - validationError: Object.values(constraints)[0] + validationError: Object.values(constraints ?? {})[0] }); } } diff --git a/libs/common/src/lib/validators/is-currency-code.ts b/libs/common/src/lib/validators/is-currency-code.ts index 76c6f4fe2..52d99816b 100644 --- a/libs/common/src/lib/validators/is-currency-code.ts +++ b/libs/common/src/lib/validators/is-currency-code.ts @@ -9,7 +9,7 @@ import { import { isISO4217CurrencyCode } from 'class-validator'; export function IsCurrencyCode(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { + return function (object: object, propertyName: string) { registerDecorator({ propertyName, constraints: [], diff --git a/libs/common/tsconfig.json b/libs/common/tsconfig.json index a14e0fc44..2b4603b71 100644 --- a/libs/common/tsconfig.json +++ b/libs/common/tsconfig.json @@ -12,6 +12,7 @@ ], "compilerOptions": { "module": "preserve", - "lib": ["dom", "es2022"] + "lib": ["dom", "es2022"], + "strictNullChecks": true } } diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.html b/libs/ui/src/lib/accounts-table/accounts-table.component.html index f76a5d676..68ae78474 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.html +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -115,21 +115,21 @@ > - + # Activities - {{ element.transactionCount }} + {{ element.activitiesCount }} - {{ transactionCount }} + {{ activitiesCount }} @@ -323,7 +323,7 @@