From b616274380544b59a26ce48b96365f998966dee9 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Wed, 12 Feb 2025 01:47:30 +0530 Subject: [PATCH 01/71] Feature/add regional market cluster risk for Japan (#4309) * Add regional market cluster risk for Japan * Update changelog --- CHANGELOG.md | 1 + .../src/app/portfolio/portfolio.service.ts | 6 ++ apps/api/src/app/user/user.service.ts | 6 ++ .../regional-market-cluster-risk/japan.ts | 77 +++++++++++++++++++ .../x-ray-rules-settings.interface.ts | 1 + 5 files changed, 91 insertions(+) create mode 100644 apps/api/src/models/rules/regional-market-cluster-risk/japan.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 349c140a3..f4f806b93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Japan) - Extended the tags selector component by a `readonly` attribute - Extended the tags selector component to support creating custom tags - Added global styles to the _Storybook_ setup diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 72568f37a..5fdb10036 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -17,6 +17,7 @@ import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/ import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; import { RegionalMarketClusterRiskEurope } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/europe'; +import { RegionalMarketClusterRiskJapan } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/japan'; import { RegionalMarketClusterRiskNorthAmerica } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/north-america'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; @@ -1290,6 +1291,11 @@ export class PortfolioService { marketsAdvancedTotalInBaseCurrency, marketsAdvanced.europe.valueInBaseCurrency ), + new RegionalMarketClusterRiskJapan( + this.exchangeRateDataService, + marketsAdvancedTotalInBaseCurrency, + marketsAdvanced.japan.valueInBaseCurrency + ), new RegionalMarketClusterRiskNorthAmerica( this.exchangeRateDataService, marketsAdvancedTotalInBaseCurrency, diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 1dae9d45b..13b067cfa 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -15,6 +15,7 @@ import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/ import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; import { RegionalMarketClusterRiskEurope } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/europe'; +import { RegionalMarketClusterRiskJapan } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/japan'; import { RegionalMarketClusterRiskNorthAmerica } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/north-america'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; @@ -283,6 +284,11 @@ export class UserService { undefined, undefined ).getSettings(user.Settings.settings), + RegionalMarketClusterRiskJapan: new RegionalMarketClusterRiskJapan( + undefined, + undefined, + undefined + ).getSettings(user.Settings.settings), RegionalMarketClusterRiskNorthAmerica: new RegionalMarketClusterRiskNorthAmerica( undefined, diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts b/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts new file mode 100644 index 000000000..4694b0006 --- /dev/null +++ b/apps/api/src/models/rules/regional-market-cluster-risk/japan.ts @@ -0,0 +1,77 @@ +import { Rule } from '@ghostfolio/api/models/rule'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { UserSettings } from '@ghostfolio/common/interfaces'; + +import { Settings } from './interfaces/rule-settings.interface'; + +export class RegionalMarketClusterRiskJapan extends Rule { + private currentValueInBaseCurrency: number; + private japanValueInBaseCurrency: number; + + public constructor( + protected exchangeRateDataService: ExchangeRateDataService, + currentValueInBaseCurrency: number, + japanValueInBaseCurrency: number + ) { + super(exchangeRateDataService, { + key: RegionalMarketClusterRiskJapan.name, + name: 'Japan' + }); + + this.currentValueInBaseCurrency = currentValueInBaseCurrency; + this.japanValueInBaseCurrency = japanValueInBaseCurrency; + } + + public evaluate(ruleSettings: Settings) { + const japanMarketValueRatio = this.currentValueInBaseCurrency + ? this.japanValueInBaseCurrency / this.currentValueInBaseCurrency + : 0; + + if (japanMarketValueRatio > ruleSettings.thresholdMax) { + return { + evaluation: `The Japan market contribution of your current investment (${(japanMarketValueRatio * 100).toPrecision(3)}%) exceeds ${( + ruleSettings.thresholdMax * 100 + ).toPrecision(3)}%`, + value: false + }; + } else if (japanMarketValueRatio < ruleSettings.thresholdMin) { + return { + evaluation: `The Japan market contribution of your current investment (${(japanMarketValueRatio * 100).toPrecision(3)}%) is below ${( + ruleSettings.thresholdMin * 100 + ).toPrecision(3)}%`, + value: false + }; + } + + return { + evaluation: `The Japan market contribution of your current investment (${(japanMarketValueRatio * 100).toPrecision(3)}%) is within the range of ${( + ruleSettings.thresholdMin * 100 + ).toPrecision( + 3 + )}% and ${(ruleSettings.thresholdMax * 100).toPrecision(3)}%`, + value: true + }; + } + + public getConfiguration() { + return { + threshold: { + max: 1, + min: 0, + step: 0.01, + unit: '%' + }, + thresholdMax: true, + thresholdMin: true + }; + } + + public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { + return { + baseCurrency, + isActive: xRayRules?.[this.getKey()]?.isActive ?? true, + thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.06, + thresholdMin: xRayRules?.[this.getKey()]?.thresholdMin ?? 0.04 + }; + } +} diff --git a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts index 4a31ef7b2..e81256edd 100644 --- a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts +++ b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts @@ -11,6 +11,7 @@ export interface XRayRulesSettings { FeeRatioInitialInvestment?: RuleSettings; RegionalMarketClusterRiskEmergingMarkets?: RuleSettings; RegionalMarketClusterRiskEurope?: RuleSettings; + RegionalMarketClusterRiskJapan?: RuleSettings; RegionalMarketClusterRiskNorthAmerica?: RuleSettings; } From c7f39d3884f964ad51291f89f29550c44c3b4535 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:17:01 +0100 Subject: [PATCH 02/71] Feature/exclude manual data source from encoding (#4307) * Exclude MANUAL data source from encoding --- .../transform-data-source-in-response.interceptor.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 f5034927c..fcbf3e76e 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 @@ -33,9 +33,12 @@ export class TransformDataSourceInResponseInterceptor attribute: 'dataSource', valueMap: Object.keys(DataSource).reduce( (valueMap, dataSource) => { - valueMap[dataSource] = encodeDataSource( - DataSource[dataSource] - ); + if (!['MANUAL'].includes(dataSource)) { + valueMap[dataSource] = encodeDataSource( + DataSource[dataSource] + ); + } + return valueMap; }, {} From ece8c80aa1e3ffc82dcb5c4bdc2bb3fe97414c88 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Thu, 13 Feb 2025 01:48:35 +0530 Subject: [PATCH 03/71] Feature/regional market cluster risk for Asia-Pacific (#4313) * Add regional market cluster risk for Asia-Pacific * Update changelog --- CHANGELOG.md | 1 + .../src/app/portfolio/portfolio.service.ts | 6 ++ apps/api/src/app/user/user.service.ts | 7 ++ .../asia-pacific.ts | 77 +++++++++++++++++++ .../x-ray-rules-settings.interface.ts | 1 + 5 files changed, 92 insertions(+) create mode 100644 apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f4f806b93..9e65772d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Asia-Pacific Markets) - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Japan) - Extended the tags selector component by a `readonly` attribute - Extended the tags selector component to support creating custom tags diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 5fdb10036..811c59f9d 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -15,6 +15,7 @@ import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/model import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup'; import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; +import { RegionalMarketClusterRiskAsiaPacific } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/asia-pacific'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; import { RegionalMarketClusterRiskEurope } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/europe'; import { RegionalMarketClusterRiskJapan } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/japan'; @@ -1281,6 +1282,11 @@ export class PortfolioService { summary.ordersCount > 0 ? await this.rulesService.evaluate( [ + new RegionalMarketClusterRiskAsiaPacific( + this.exchangeRateDataService, + marketsAdvancedTotalInBaseCurrency, + marketsAdvanced.asiaPacific.valueInBaseCurrency + ), new RegionalMarketClusterRiskEmergingMarkets( this.exchangeRateDataService, marketsAdvancedTotalInBaseCurrency, diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 13b067cfa..7665e43d9 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -13,6 +13,7 @@ import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/model import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup'; import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; +import { RegionalMarketClusterRiskAsiaPacific } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/asia-pacific'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; import { RegionalMarketClusterRiskEurope } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/europe'; import { RegionalMarketClusterRiskJapan } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/japan'; @@ -273,6 +274,12 @@ export class UserService { undefined, undefined ).getSettings(user.Settings.settings), + RegionalMarketClusterRiskAsiaPacific: + new RegionalMarketClusterRiskAsiaPacific( + undefined, + undefined, + undefined + ).getSettings(user.Settings.settings), RegionalMarketClusterRiskEmergingMarkets: new RegionalMarketClusterRiskEmergingMarkets( undefined, diff --git a/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts b/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts new file mode 100644 index 000000000..d49849d54 --- /dev/null +++ b/apps/api/src/models/rules/regional-market-cluster-risk/asia-pacific.ts @@ -0,0 +1,77 @@ +import { Rule } from '@ghostfolio/api/models/rule'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { UserSettings } from '@ghostfolio/common/interfaces'; + +import { Settings } from './interfaces/rule-settings.interface'; + +export class RegionalMarketClusterRiskAsiaPacific extends Rule { + private asiaPacificValueInBaseCurrency: number; + private currentValueInBaseCurrency: number; + + public constructor( + protected exchangeRateDataService: ExchangeRateDataService, + currentValueInBaseCurrency: number, + asiaPacificValueInBaseCurrency: number + ) { + super(exchangeRateDataService, { + key: RegionalMarketClusterRiskAsiaPacific.name, + name: 'Asia-Pacific' + }); + + this.asiaPacificValueInBaseCurrency = asiaPacificValueInBaseCurrency; + this.currentValueInBaseCurrency = currentValueInBaseCurrency; + } + + public evaluate(ruleSettings: Settings) { + const asiaPacificMarketValueRatio = this.currentValueInBaseCurrency + ? this.asiaPacificValueInBaseCurrency / this.currentValueInBaseCurrency + : 0; + + if (asiaPacificMarketValueRatio > ruleSettings.thresholdMax) { + return { + evaluation: `The Asia-Pacific market contribution of your current investment (${(asiaPacificMarketValueRatio * 100).toPrecision(3)}%) exceeds ${( + ruleSettings.thresholdMax * 100 + ).toPrecision(3)}%`, + value: false + }; + } else if (asiaPacificMarketValueRatio < ruleSettings.thresholdMin) { + return { + evaluation: `The Asia-Pacific market contribution of your current investment (${(asiaPacificMarketValueRatio * 100).toPrecision(3)}%) is below ${( + ruleSettings.thresholdMin * 100 + ).toPrecision(3)}%`, + value: false + }; + } + + return { + evaluation: `The Asia-Pacific market contribution of your current investment (${(asiaPacificMarketValueRatio * 100).toPrecision(3)}%) is within the range of ${( + ruleSettings.thresholdMin * 100 + ).toPrecision( + 3 + )}% and ${(ruleSettings.thresholdMax * 100).toPrecision(3)}%`, + value: true + }; + } + + public getConfiguration() { + return { + threshold: { + max: 1, + min: 0, + step: 0.01, + unit: '%' + }, + thresholdMax: true, + thresholdMin: true + }; + } + + public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { + return { + baseCurrency, + isActive: xRayRules?.[this.getKey()]?.isActive ?? true, + thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.03, + thresholdMin: xRayRules?.[this.getKey()]?.thresholdMin ?? 0.02 + }; + } +} diff --git a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts index e81256edd..9ae32d802 100644 --- a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts +++ b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts @@ -9,6 +9,7 @@ export interface XRayRulesSettings { EconomicMarketClusterRiskEmergingMarkets?: RuleSettings; EmergencyFundSetup?: RuleSettings; FeeRatioInitialInvestment?: RuleSettings; + RegionalMarketClusterRiskAsiaPacific?: RuleSettings; RegionalMarketClusterRiskEmergingMarkets?: RuleSettings; RegionalMarketClusterRiskEurope?: RuleSettings; RegionalMarketClusterRiskJapan?: RuleSettings; From ab379f9abfe60e9631a452ac3ad27cb66b39a65e Mon Sep 17 00:00:00 2001 From: Amandee Ellawala <47607256+amandee27@users.noreply.github.com> Date: Wed, 12 Feb 2025 20:21:31 +0000 Subject: [PATCH 04/71] Feature/extend holding detail dialog by historical market data editor (#4281) * Extend holding detail dialog by historical market data editor * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/user/user.service.ts | 5 +- .../holding-detail-dialog.component.ts | 48 ++++++++++++++++++- .../holding-detail-dialog.html | 21 ++++++++ ...storical-market-data-editor.component.html | 1 + 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e65772d1..32623c528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Japan) - Extended the tags selector component by a `readonly` attribute - Extended the tags selector component to support creating custom tags +- Extended the holding detail dialog by the historical market data editor (experimental) - Added global styles to the _Storybook_ setup ### Changed diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 7665e43d9..30d10c8d6 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -346,7 +346,10 @@ export class UserService { currentPermissions, permissions.accessHoldingsChart, permissions.createAccess, - permissions.readAiPrompt + permissions.createMarketDataOfOwnAssetProfile, + permissions.readAiPrompt, + permissions.readMarketDataOfOwnAssetProfile, + permissions.updateMarketDataOfOwnAssetProfile ); // Reset benchmark diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 297a990ec..4f7e4efd4 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -13,8 +13,10 @@ import { LineChartItem, User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfDataProviderCreditsComponent } from '@ghostfolio/ui/data-provider-credits'; +import { GfHistoricalMarketDataEditorComponent } from '@ghostfolio/ui/historical-market-data-editor'; import { translate } from '@ghostfolio/ui/i18n'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart'; @@ -44,7 +46,7 @@ import { SortDirection } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { Router } from '@angular/router'; -import { Account, Tag } from '@prisma/client'; +import { Account, MarketData, Tag } from '@prisma/client'; import { format, isSameMonth, isToday, parseISO } from 'date-fns'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; @@ -62,6 +64,7 @@ import { HoldingDetailDialogParams } from './interfaces/interfaces'; GfDataProviderCreditsComponent, GfDialogFooterModule, GfDialogHeaderModule, + GfHistoricalMarketDataEditorComponent, GfLineChartComponent, GfPortfolioProportionChartComponent, GfTagsSelectorComponent, @@ -95,9 +98,11 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { public dividendYieldPercentWithCurrencyEffect: number; public feeInBaseCurrency: number; public firstBuyDate: string; + public hasPermissionToReadMarketDataOfOwnAssetProfile: boolean; public historicalDataItems: LineChartItem[]; public investment: number; public investmentPrecision = 2; + public marketDataItems: MarketData[] = []; public marketPrice: number; public maxPrice: number; public minPrice: number; @@ -231,6 +236,14 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.feeInBaseCurrency = feeInBaseCurrency; this.firstBuyDate = firstBuyDate; + this.hasPermissionToReadMarketDataOfOwnAssetProfile = + hasPermission( + this.user?.permissions, + permissions.readMarketDataOfOwnAssetProfile + ) && + SymbolProfile?.dataSource === 'MANUAL' && + SymbolProfile?.userId === this.user?.id; + this.historicalDataItems = historicalData.map( ({ averagePrice, date, marketPrice }) => { this.benchmarkDataItems.push({ @@ -393,6 +406,10 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { } ); + if (this.hasPermissionToReadMarketDataOfOwnAssetProfile) { + this.fetchMarketData(); + } + this.changeDetectorRef.markForCheck(); } ); @@ -448,6 +465,12 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { }); } + public onMarketDataChanged(withRefresh = false) { + if (withRefresh) { + this.fetchMarketData(); + } + } + public onTagsChanged(tags: Tag[]) { this.activityForm.get('tags').setValue(tags); } @@ -464,4 +487,27 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.unsubscribeSubject.next(); this.unsubscribeSubject.complete(); } + + private fetchMarketData() { + this.dataService + .fetchMarketDataBySymbol({ + dataSource: this.data.dataSource, + symbol: this.data.symbol + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ marketData }) => { + this.marketDataItems = marketData; + + this.historicalDataItems = this.marketDataItems.map( + ({ date, marketPrice }) => { + return { + date: format(date, DATE_FORMAT), + value: marketPrice + }; + } + ); + + this.changeDetectorRef.markForCheck(); + }); + } } 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 d820ddf7d..e7b3cc1b2 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 @@ -364,6 +364,27 @@ [showValueInBaseCurrency]="false" /> + @if ( + hasPermissionToReadMarketDataOfOwnAssetProfile && + user?.settings?.isExperimentalFeatures + ) { + + + +
Market Data
+
+ +
+ } From 58dfba8e63d4f416194ea5585d08517bdc0200e3 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 14 Feb 2025 20:55:34 +0100 Subject: [PATCH 05/71] Feature/upgrade @trivago/prettier-plugin-sort-imports to version 5.2.2 (#4315) * Upgrade @trivago/prettier-plugin-sort-imports to version 5.2.2 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 66 +++++++++++++++++++++++------------------------ package.json | 2 +- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32623c528..dbcd724fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the language localization for German (`de`) +- Upgraded `@trivago/prettier-plugin-sort-imports` from version `5.2.1` to `5.2.2` ## 2.138.0 - 2025-02-08 diff --git a/package-lock.json b/package-lock.json index ec5cb3cb6..e015f580e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -125,7 +125,7 @@ "@storybook/addon-interactions": "8.4.7", "@storybook/angular": "8.4.7", "@storybook/core-server": "8.4.7", - "@trivago/prettier-plugin-sort-imports": "5.2.1", + "@trivago/prettier-plugin-sort-imports": "5.2.2", "@types/big.js": "6.2.2", "@types/cache-manager": "4.0.6", "@types/color": "4.2.0", @@ -2449,13 +2449,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", - "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz", + "integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.3", - "@babel/types": "^7.26.3", + "@babel/parser": "^7.26.8", + "@babel/types": "^7.26.8", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -2766,12 +2766,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", - "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz", + "integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.3" + "@babel/types": "^7.26.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -4149,30 +4149,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz", + "integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.8", + "@babel/types": "^7.26.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", - "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz", + "integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.3", - "@babel/parser": "^7.26.3", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.3", + "@babel/generator": "^7.26.8", + "@babel/parser": "^7.26.8", + "@babel/template": "^7.26.8", + "@babel/types": "^7.26.8", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -4181,9 +4181,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", - "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz", + "integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -10472,16 +10472,16 @@ } }, "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.1.tgz", - "integrity": "sha512-NDZndt0fmVThIx/8cExuJHLZagUVzfGCoVrwH9x6aZvwfBdkrDFTYujecek6X2WpG4uUFsVaPg5+aNQPSyjcmw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz", + "integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@babel/generator": "^7.26.2", - "@babel/parser": "^7.26.2", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.7", + "@babel/traverse": "^7.26.7", + "@babel/types": "^7.26.7", "javascript-natural-sort": "^0.7.1", "lodash": "^4.17.21" }, diff --git a/package.json b/package.json index 7c9fda80c..e3043de16 100644 --- a/package.json +++ b/package.json @@ -171,7 +171,7 @@ "@storybook/addon-interactions": "8.4.7", "@storybook/angular": "8.4.7", "@storybook/core-server": "8.4.7", - "@trivago/prettier-plugin-sort-imports": "5.2.1", + "@trivago/prettier-plugin-sort-imports": "5.2.2", "@types/big.js": "6.2.2", "@types/cache-manager": "4.0.6", "@types/color": "4.2.0", From ec8fce44a62063897a56ae7017c6dfd26b4556c9 Mon Sep 17 00:00:00 2001 From: Ken Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:48:53 +0700 Subject: [PATCH 06/71] Feature/allow creating custom tags from holding detail dialog component (#4308) * Allow creating custom tags from holding detail dialog component * Extend create tag endpoint * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 1 + apps/api/src/app/tag/create-tag.dto.ts | 6 ++- apps/api/src/app/tag/tag.controller.ts | 39 ++++++++++++-- apps/api/src/app/tag/update-tag.dto.ts | 6 ++- apps/api/src/app/user/user.service.ts | 1 + .../holding-detail-dialog.component.ts | 53 +++++++++++++++---- .../holding-detail-dialog.html | 1 + libs/common/src/lib/permissions.ts | 3 ++ .../tags-selector.component.html | 2 +- .../tags-selector.component.stories.ts | 3 +- .../tags-selector/tags-selector.component.ts | 4 +- 11 files changed, 99 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbcd724fe..37bc84cf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Asia-Pacific Markets) - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Japan) +- Added support to create custom tags in the holding detail dialog - Extended the tags selector component by a `readonly` attribute - Extended the tags selector component to support creating custom tags - Extended the holding detail dialog by the historical market data editor (experimental) diff --git a/apps/api/src/app/tag/create-tag.dto.ts b/apps/api/src/app/tag/create-tag.dto.ts index 650a0ce12..09c29d25a 100644 --- a/apps/api/src/app/tag/create-tag.dto.ts +++ b/apps/api/src/app/tag/create-tag.dto.ts @@ -1,6 +1,10 @@ -import { IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; export class CreateTagDto { @IsString() name: string; + + @IsOptional() + @IsString() + userId?: string; } diff --git a/apps/api/src/app/tag/tag.controller.ts b/apps/api/src/app/tag/tag.controller.ts index 6198a0bf5..862f0a708 100644 --- a/apps/api/src/app/tag/tag.controller.ts +++ b/apps/api/src/app/tag/tag.controller.ts @@ -1,6 +1,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; -import { permissions } from '@ghostfolio/common/permissions'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { RequestWithUser } from '@ghostfolio/common/types'; import { Body, @@ -8,11 +9,13 @@ import { Delete, Get, HttpException, + Inject, Param, Post, Put, UseGuards } from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { Tag } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; @@ -23,7 +26,10 @@ import { UpdateTagDto } from './update-tag.dto'; @Controller('tag') export class TagController { - public constructor(private readonly tagService: TagService) {} + public constructor( + @Inject(REQUEST) private readonly request: RequestWithUser, + private readonly tagService: TagService + ) {} @Get() @HasPermission(permissions.readTags) @@ -33,9 +39,34 @@ export class TagController { } @Post() - @HasPermission(permissions.createTag) - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseGuards(AuthGuard('jwt')) public async createTag(@Body() data: CreateTagDto): Promise { + const canCreateOwnTag = hasPermission( + this.request.user.permissions, + permissions.createOwnTag + ); + + const canCreateTag = hasPermission( + this.request.user.permissions, + permissions.createTag + ); + + if (!canCreateOwnTag && !canCreateTag) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + if (canCreateOwnTag && !canCreateTag) { + if (data.userId !== this.request.user.id) { + throw new HttpException( + getReasonPhrase(StatusCodes.BAD_REQUEST), + StatusCodes.BAD_REQUEST + ); + } + } + return this.tagService.createTag(data); } diff --git a/apps/api/src/app/tag/update-tag.dto.ts b/apps/api/src/app/tag/update-tag.dto.ts index b26ffde11..5ae42dcc6 100644 --- a/apps/api/src/app/tag/update-tag.dto.ts +++ b/apps/api/src/app/tag/update-tag.dto.ts @@ -1,4 +1,4 @@ -import { IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; export class UpdateTagDto { @IsString() @@ -6,4 +6,8 @@ export class UpdateTagDto { @IsString() name: string; + + @IsOptional() + @IsString() + userId?: string; } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 30d10c8d6..dcf9d9404 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -347,6 +347,7 @@ export class UserService { permissions.accessHoldingsChart, permissions.createAccess, permissions.createMarketDataOfOwnAssetProfile, + permissions.createOwnTag, permissions.readAiPrompt, permissions.readMarketDataOfOwnAssetProfile, permissions.updateMarketDataOfOwnAssetProfile diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 4f7e4efd4..54fab34d6 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -2,6 +2,7 @@ import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interf import { GfAccountsTableModule } from '@ghostfolio/client/components/accounts-table/accounts-table.module'; import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module'; import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module'; +import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { NUMERICAL_PRECISION_THRESHOLD } from '@ghostfolio/common/config'; @@ -50,7 +51,7 @@ import { Account, MarketData, Tag } from '@prisma/client'; import { format, isSameMonth, isToday, parseISO } from 'date-fns'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { switchMap, takeUntil } from 'rxjs/operators'; import { HoldingDetailDialogParams } from './interfaces/interfaces'; @@ -98,6 +99,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { public dividendYieldPercentWithCurrencyEffect: number; public feeInBaseCurrency: number; public firstBuyDate: string; + public hasPermissionToCreateOwnTag: boolean; public hasPermissionToReadMarketDataOfOwnAssetProfile: boolean; public historicalDataItems: LineChartItem[]; public investment: number; @@ -131,6 +133,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { private unsubscribeSubject = new Subject(); public constructor( + private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, public dialogRef: MatDialogRef, @@ -153,15 +156,40 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.activityForm .get('tags') .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((tags) => { - this.dataService - .putHoldingTags({ - tags, - dataSource: this.data.dataSource, - symbol: this.data.symbol - }) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(); + .subscribe((tags: Tag[]) => { + const newTag = tags.find(({ id }) => { + return id === undefined; + }); + + if (newTag && this.hasPermissionToCreateOwnTag) { + this.adminService + .postTag({ ...newTag, userId: this.user.id }) + .pipe( + switchMap((createdTag) => { + return this.dataService.putHoldingTags({ + dataSource: this.data.dataSource, + symbol: this.data.symbol, + tags: [ + ...tags.filter(({ id }) => { + return id !== undefined; + }), + createdTag + ] + }); + }), + takeUntil(this.unsubscribeSubject) + ) + .subscribe(); + } else { + this.dataService + .putHoldingTags({ + tags, + dataSource: this.data.dataSource, + symbol: this.data.symbol + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + } }); this.dataService @@ -420,6 +448,11 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { if (state?.user) { this.user = state.user; + this.hasPermissionToCreateOwnTag = hasPermission( + this.user.permissions, + permissions.createOwnTag + ); + this.tagsAvailable = this.user?.tags?.map((tag) => { return { 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 e7b3cc1b2..df1c0c62a 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 @@ -388,6 +388,7 @@ } - @if (hasPermissionToCreateTags && tagInputControl.value) { + @if (hasPermissionToCreateTag && tagInputControl.value) { diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts index 8d1431b46..42fb68876 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.stories.ts @@ -1,4 +1,5 @@ import { CommonModule } from '@angular/common'; +import '@angular/localize/init'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'; @@ -49,7 +50,7 @@ export const Default: Story = { export const CreateCustomTags: Story = { args: { - hasPermissionToCreateTags: true, + hasPermissionToCreateTag: true, tags: [ { id: 'EMERGENCY_FUND', diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.ts index 611c1e938..02b3a0a95 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.ts @@ -42,7 +42,7 @@ import { BehaviorSubject, Subject, takeUntil } from 'rxjs'; templateUrl: 'tags-selector.component.html' }) export class GfTagsSelectorComponent implements OnInit, OnChanges, OnDestroy { - @Input() hasPermissionToCreateTags = false; + @Input() hasPermissionToCreateTag = false; @Input() readonly = false; @Input() tags: Tag[]; @Input() tagsAvailable: Tag[]; @@ -81,7 +81,7 @@ export class GfTagsSelectorComponent implements OnInit, OnChanges, OnDestroy { return id === event.option.value; }); - if (!tag && this.hasPermissionToCreateTags) { + if (!tag && this.hasPermissionToCreateTag) { tag = { id: undefined, name: event.option.value as string, From 4f76ee67588ba5ba8b1d3ca15e90745170fd029d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Tom=C3=A1s=20Fern=C3=A1ndez=20Mart=C3=ADn?= Date: Sat, 15 Feb 2025 09:43:28 +0100 Subject: [PATCH 07/71] Feature/improve symbol lookup in Trackinsight data enhancer (#4296) * Feature: enhance Trackinsight data fetching with symbol search fallback * Feature: refactor Trackinsight symbol search for improved clarity and error handling * Fixed style concerns and removed code duplication * Minor improvements * Update changelog * Update changelog * Clean up --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 1 + .../trackinsight/trackinsight.service.ts | 83 +++++++++++-------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37bc84cf4..db1563f26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data - Improved the language localization for German (`de`) - Upgraded `@trivago/prettier-plugin-sort-imports` from version `5.2.1` to `5.2.2` diff --git a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts index 56b90082d..2b8eaf2e9 100644 --- a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts @@ -44,28 +44,31 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { return response; } + let trackinsightSymbol = await this.searchTrackinsightSymbol({ + requestTimeout, + symbol + }); + + if (!trackinsightSymbol) { + trackinsightSymbol = await this.searchTrackinsightSymbol({ + requestTimeout, + symbol: symbol.split('.')?.[0] + }); + } + + if (!trackinsightSymbol) { + return response; + } + const profile = await fetch( - `${TrackinsightDataEnhancerService.baseUrl}/funds/${symbol}.json`, + `${TrackinsightDataEnhancerService.baseUrl}/funds/${trackinsightSymbol}.json`, { signal: AbortSignal.timeout(requestTimeout) } ) .then((res) => res.json()) .catch(() => { - return fetch( - `${TrackinsightDataEnhancerService.baseUrl}/funds/${ - symbol.split('.')?.[0] - }.json`, - { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) - } - ) - .then((res) => res.json()) - .catch(() => { - return {}; - }); + return {}; }); const isin = profile?.isin?.split(';')?.[0]; @@ -75,29 +78,14 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { } const holdings = await fetch( - `${TrackinsightDataEnhancerService.baseUrl}/holdings/${symbol}.json`, + `${TrackinsightDataEnhancerService.baseUrl}/holdings/${trackinsightSymbol}.json`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ) .then((res) => res.json()) .catch(() => { - return fetch( - `${TrackinsightDataEnhancerService.baseUrl}/holdings/${ - symbol.split('.')?.[0] - }.json`, - { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) - } - ) - .then((res) => res.json()) - .catch(() => { - return {}; - }); + return {}; }); if ( @@ -180,4 +168,33 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { public getTestSymbol() { return 'QQQ'; } + + private async searchTrackinsightSymbol({ + requestTimeout, + symbol + }: { + requestTimeout: number; + symbol: string; + }) { + return fetch( + `https://www.trackinsight.com/search-api/search_v2/${symbol}/_/ticker/default/0/3`, + { + signal: AbortSignal.timeout(requestTimeout) + } + ) + .then((res) => res.json()) + .then((jsonRes) => { + if ( + jsonRes['results']?.['count'] === 1 || + jsonRes['results']?.['docs']?.[0]?.['ticker'] === symbol + ) { + return jsonRes['results']['docs'][0]['ticker']; + } + + return undefined; + }) + .catch(() => { + return undefined; + }); + } } From f1ab3ff8e85530106a9e904907ea36a5c5f5cf7c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 15 Feb 2025 10:00:14 +0100 Subject: [PATCH 08/71] Feature/modernize tags endpoint (#4317) * Modernize tags endpoint * Update changelog --- CHANGELOG.md | 2 +- apps/api/src/app/app.module.ts | 4 +- .../{tag => endpoints/tags}/create-tag.dto.ts | 0 .../tags/tags.controller.ts} | 50 ++++++------ .../api/src/app/endpoints/tags/tags.module.ts | 12 +++ .../{tag => endpoints/tags}/update-tag.dto.ts | 0 apps/api/src/app/tag/tag.module.ts | 14 ---- apps/api/src/app/tag/tag.service.ts | 81 ------------------- apps/api/src/services/tag/tag.service.ts | 73 +++++++++++++++++ .../admin-tag/admin-tag.component.ts | 14 ++-- .../create-or-update-tag-dialog.component.ts | 4 +- .../holding-detail-dialog.component.ts | 4 +- .../holding-detail-dialog.html | 4 +- apps/client/src/app/services/admin.service.ts | 20 +---- apps/client/src/app/services/data.service.ts | 18 +++++ 15 files changed, 144 insertions(+), 156 deletions(-) rename apps/api/src/app/{tag => endpoints/tags}/create-tag.dto.ts (100%) rename apps/api/src/app/{tag/tag.controller.ts => endpoints/tags/tags.controller.ts} (95%) create mode 100644 apps/api/src/app/endpoints/tags/tags.module.ts rename apps/api/src/app/{tag => endpoints/tags}/update-tag.dto.ts (100%) delete mode 100644 apps/api/src/app/tag/tag.module.ts delete mode 100644 apps/api/src/app/tag/tag.service.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index db1563f26..c5e982369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Asia-Pacific Markets) - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Japan) -- Added support to create custom tags in the holding detail dialog +- Added support to create custom tags in the holding detail dialog (experimental) - Extended the tags selector component by a `readonly` attribute - Extended the tags selector component to support creating custom tags - Extended the holding detail dialog by the historical market data editor (experimental) diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 6d097aeff..3e68bf428 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -36,6 +36,7 @@ import { ApiKeysModule } from './endpoints/api-keys/api-keys.module'; import { GhostfolioModule } from './endpoints/data-providers/ghostfolio/ghostfolio.module'; import { MarketDataModule } from './endpoints/market-data/market-data.module'; import { PublicModule } from './endpoints/public/public.module'; +import { TagsModule } from './endpoints/tags/tags.module'; import { ExchangeRateModule } from './exchange-rate/exchange-rate.module'; import { ExportModule } from './export/export.module'; import { HealthModule } from './health/health.module'; @@ -49,7 +50,6 @@ import { RedisCacheModule } from './redis-cache/redis-cache.module'; import { SitemapModule } from './sitemap/sitemap.module'; import { SubscriptionModule } from './subscription/subscription.module'; import { SymbolModule } from './symbol/symbol.module'; -import { TagModule } from './tag/tag.module'; import { UserModule } from './user/user.module'; @Module({ @@ -124,7 +124,7 @@ import { UserModule } from './user/user.module'; SitemapModule, SubscriptionModule, SymbolModule, - TagModule, + TagsModule, TwitterBotModule, UserModule ], diff --git a/apps/api/src/app/tag/create-tag.dto.ts b/apps/api/src/app/endpoints/tags/create-tag.dto.ts similarity index 100% rename from apps/api/src/app/tag/create-tag.dto.ts rename to apps/api/src/app/endpoints/tags/create-tag.dto.ts diff --git a/apps/api/src/app/tag/tag.controller.ts b/apps/api/src/app/endpoints/tags/tags.controller.ts similarity index 95% rename from apps/api/src/app/tag/tag.controller.ts rename to apps/api/src/app/endpoints/tags/tags.controller.ts index 862f0a708..bf216bb21 100644 --- a/apps/api/src/app/tag/tag.controller.ts +++ b/apps/api/src/app/endpoints/tags/tags.controller.ts @@ -1,5 +1,6 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { RequestWithUser } from '@ghostfolio/common/types'; @@ -21,23 +22,15 @@ import { Tag } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { CreateTagDto } from './create-tag.dto'; -import { TagService } from './tag.service'; import { UpdateTagDto } from './update-tag.dto'; -@Controller('tag') -export class TagController { +@Controller('tags') +export class TagsController { public constructor( @Inject(REQUEST) private readonly request: RequestWithUser, private readonly tagService: TagService ) {} - @Get() - @HasPermission(permissions.readTags) - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async getTags() { - return this.tagService.getTagsWithActivityCount(); - } - @Post() @UseGuards(AuthGuard('jwt')) public async createTag(@Body() data: CreateTagDto): Promise { @@ -70,10 +63,10 @@ export class TagController { return this.tagService.createTag(data); } - @HasPermission(permissions.updateTag) - @Put(':id') + @Delete(':id') + @HasPermission(permissions.deleteTag) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async updateTag(@Param('id') id: string, @Body() data: UpdateTagDto) { + public async deleteTag(@Param('id') id: string) { const originalTag = await this.tagService.getTag({ id }); @@ -85,20 +78,20 @@ export class TagController { ); } - return this.tagService.updateTag({ - data: { - ...data - }, - where: { - id - } - }); + return this.tagService.deleteTag({ id }); } - @Delete(':id') - @HasPermission(permissions.deleteTag) + @Get() + @HasPermission(permissions.readTags) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async deleteTag(@Param('id') id: string) { + public async getTags() { + return this.tagService.getTagsWithActivityCount(); + } + + @HasPermission(permissions.updateTag) + @Put(':id') + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async updateTag(@Param('id') id: string, @Body() data: UpdateTagDto) { const originalTag = await this.tagService.getTag({ id }); @@ -110,6 +103,13 @@ export class TagController { ); } - return this.tagService.deleteTag({ id }); + return this.tagService.updateTag({ + data: { + ...data + }, + where: { + id + } + }); } } diff --git a/apps/api/src/app/endpoints/tags/tags.module.ts b/apps/api/src/app/endpoints/tags/tags.module.ts new file mode 100644 index 000000000..a8a2f1c51 --- /dev/null +++ b/apps/api/src/app/endpoints/tags/tags.module.ts @@ -0,0 +1,12 @@ +import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { TagModule } from '@ghostfolio/api/services/tag/tag.module'; + +import { Module } from '@nestjs/common'; + +import { TagsController } from './tags.controller'; + +@Module({ + controllers: [TagsController], + imports: [PrismaModule, TagModule] +}) +export class TagsModule {} diff --git a/apps/api/src/app/tag/update-tag.dto.ts b/apps/api/src/app/endpoints/tags/update-tag.dto.ts similarity index 100% rename from apps/api/src/app/tag/update-tag.dto.ts rename to apps/api/src/app/endpoints/tags/update-tag.dto.ts diff --git a/apps/api/src/app/tag/tag.module.ts b/apps/api/src/app/tag/tag.module.ts deleted file mode 100644 index 48587c54e..000000000 --- a/apps/api/src/app/tag/tag.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; - -import { Module } from '@nestjs/common'; - -import { TagController } from './tag.controller'; -import { TagService } from './tag.service'; - -@Module({ - controllers: [TagController], - exports: [TagService], - imports: [PrismaModule], - providers: [TagService] -}) -export class TagModule {} diff --git a/apps/api/src/app/tag/tag.service.ts b/apps/api/src/app/tag/tag.service.ts deleted file mode 100644 index c4a5447ac..000000000 --- a/apps/api/src/app/tag/tag.service.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; - -import { Injectable } from '@nestjs/common'; -import { Prisma, Tag } from '@prisma/client'; - -@Injectable() -export class TagService { - public constructor(private readonly prismaService: PrismaService) {} - - public async createTag(data: Prisma.TagCreateInput) { - return this.prismaService.tag.create({ - data - }); - } - - public async deleteTag(where: Prisma.TagWhereUniqueInput): Promise { - return this.prismaService.tag.delete({ where }); - } - - public async getTag( - tagWhereUniqueInput: Prisma.TagWhereUniqueInput - ): Promise { - return this.prismaService.tag.findUnique({ - where: tagWhereUniqueInput - }); - } - - public async getTags({ - cursor, - orderBy, - skip, - take, - where - }: { - cursor?: Prisma.TagWhereUniqueInput; - orderBy?: Prisma.TagOrderByWithRelationInput; - skip?: number; - take?: number; - where?: Prisma.TagWhereInput; - } = {}) { - return this.prismaService.tag.findMany({ - cursor, - orderBy, - skip, - take, - where - }); - } - - public async getTagsWithActivityCount() { - const tagsWithOrderCount = await this.prismaService.tag.findMany({ - include: { - _count: { - select: { orders: true } - } - } - }); - - return tagsWithOrderCount.map(({ _count, id, name, userId }) => { - return { - id, - name, - userId, - activityCount: _count.orders - }; - }); - } - - public async updateTag({ - data, - where - }: { - data: Prisma.TagUpdateInput; - where: Prisma.TagWhereUniqueInput; - }): Promise { - return this.prismaService.tag.update({ - data, - where - }); - } -} diff --git a/apps/api/src/services/tag/tag.service.ts b/apps/api/src/services/tag/tag.service.ts index b16f22fbb..3d6bd3907 100644 --- a/apps/api/src/services/tag/tag.service.ts +++ b/apps/api/src/services/tag/tag.service.ts @@ -1,11 +1,52 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { Injectable } from '@nestjs/common'; +import { Prisma, Tag } from '@prisma/client'; @Injectable() export class TagService { public constructor(private readonly prismaService: PrismaService) {} + public async createTag(data: Prisma.TagCreateInput) { + return this.prismaService.tag.create({ + data + }); + } + + public async deleteTag(where: Prisma.TagWhereUniqueInput): Promise { + return this.prismaService.tag.delete({ where }); + } + + public async getTag( + tagWhereUniqueInput: Prisma.TagWhereUniqueInput + ): Promise { + return this.prismaService.tag.findUnique({ + where: tagWhereUniqueInput + }); + } + + public async getTags({ + cursor, + orderBy, + skip, + take, + where + }: { + cursor?: Prisma.TagWhereUniqueInput; + orderBy?: Prisma.TagOrderByWithRelationInput; + skip?: number; + take?: number; + where?: Prisma.TagWhereInput; + } = {}) { + return this.prismaService.tag.findMany({ + cursor, + orderBy, + skip, + take, + where + }); + } + public async getTagsForUser(userId: string) { const tags = await this.prismaService.tag.findMany({ include: { @@ -41,4 +82,36 @@ export class TagService { isUsed: _count.orders > 0 })); } + + public async getTagsWithActivityCount() { + const tagsWithOrderCount = await this.prismaService.tag.findMany({ + include: { + _count: { + select: { orders: true } + } + } + }); + + return tagsWithOrderCount.map(({ _count, id, name, userId }) => { + return { + id, + name, + userId, + activityCount: _count.orders + }; + }); + } + + public async updateTag({ + data, + where + }: { + data: Prisma.TagUpdateInput; + where: Prisma.TagWhereUniqueInput; + }): Promise { + return this.prismaService.tag.update({ + data, + where + }); + } } diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.ts b/apps/client/src/app/components/admin-tag/admin-tag.component.ts index 3c0bdb684..bd7432b33 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.ts +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.ts @@ -1,8 +1,7 @@ -import { CreateTagDto } from '@ghostfolio/api/app/tag/create-tag.dto'; -import { UpdateTagDto } from '@ghostfolio/api/app/tag/update-tag.dto'; +import { CreateTagDto } from '@ghostfolio/api/app/endpoints/tags/create-tag.dto'; +import { UpdateTagDto } from '@ghostfolio/api/app/endpoints/tags/update-tag.dto'; import { ConfirmationDialogType } from '@ghostfolio/client/core/notification/confirmation-dialog/confirmation-dialog.type'; import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; -import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; @@ -43,7 +42,6 @@ export class AdminTagComponent implements OnInit, OnDestroy { private unsubscribeSubject = new Subject(); public constructor( - private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, private deviceService: DeviceDetectorService, @@ -100,7 +98,7 @@ export class AdminTagComponent implements OnInit, OnDestroy { } private deleteTag(aId: string) { - this.adminService + this.dataService .deleteTag(aId) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe({ @@ -116,7 +114,7 @@ export class AdminTagComponent implements OnInit, OnDestroy { } private fetchTags() { - this.adminService + this.dataService .fetchTags() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((tags) => { @@ -148,7 +146,7 @@ export class AdminTagComponent implements OnInit, OnDestroy { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((tag: CreateTagDto | null) => { if (tag) { - this.adminService + this.dataService .postTag(tag) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe({ @@ -184,7 +182,7 @@ export class AdminTagComponent implements OnInit, OnDestroy { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((tag: UpdateTagDto | null) => { if (tag) { - this.adminService + this.dataService .putTag(tag) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe({ diff --git a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts index 9b7194cc6..1bbda8e13 100644 --- a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts +++ b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts @@ -1,5 +1,5 @@ -import { CreateTagDto } from '@ghostfolio/api/app/tag/create-tag.dto'; -import { UpdateTagDto } from '@ghostfolio/api/app/tag/update-tag.dto'; +import { CreateTagDto } from '@ghostfolio/api/app/endpoints/tags/create-tag.dto'; +import { UpdateTagDto } from '@ghostfolio/api/app/endpoints/tags/update-tag.dto'; import { validateObjectForForm } from '@ghostfolio/client/util/form.util'; import { diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 54fab34d6..69322b216 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -2,7 +2,6 @@ import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interf import { GfAccountsTableModule } from '@ghostfolio/client/components/accounts-table/accounts-table.module'; import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module'; import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module'; -import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { NUMERICAL_PRECISION_THRESHOLD } from '@ghostfolio/common/config'; @@ -133,7 +132,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { private unsubscribeSubject = new Subject(); public constructor( - private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, public dialogRef: MatDialogRef, @@ -162,7 +160,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { }); if (newTag && this.hasPermissionToCreateOwnTag) { - this.adminService + this.dataService .postTag({ ...newTag, userId: this.user.id }) .pipe( switchMap((createdTag) => { 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 df1c0c62a..a767a5796 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 @@ -388,7 +388,9 @@ (`/api/v1/tag/${aId}`); - } - public executeJob(aId: string) { return this.http.get(`/api/v1/admin/queue/job/${aId}/execute`); } @@ -155,10 +149,6 @@ export class AdminService { return this.http.get('/api/v1/platform'); } - public fetchTags() { - return this.http.get('/api/v1/tag'); - } - public fetchUsers({ skip, take = DEFAULT_PAGE_SIZE @@ -261,10 +251,6 @@ export class AdminService { return this.http.post(`/api/v1/platform`, aPlatform); } - public postTag(aTag: CreateTagDto) { - return this.http.post(`/api/v1/tag`, aTag); - } - public putPlatform(aPlatform: UpdatePlatformDto) { return this.http.put( `/api/v1/platform/${aPlatform.id}`, @@ -272,10 +258,6 @@ export class AdminService { ); } - public putTag(aTag: UpdateTagDto) { - return this.http.put(`/api/v1/tag/${aTag.id}`, aTag); - } - public testMarketData({ dataSource, scraperConfiguration, diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 4a57d5878..0da1275e6 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -4,6 +4,8 @@ import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto import { TransferBalanceDto } from '@ghostfolio/api/app/account/transfer-balance.dto'; import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto'; import { UpdateBulkMarketDataDto } from '@ghostfolio/api/app/admin/update-bulk-market-data.dto'; +import { CreateTagDto } from '@ghostfolio/api/app/endpoints/tags/create-tag.dto'; +import { UpdateTagDto } from '@ghostfolio/api/app/endpoints/tags/update-tag.dto'; import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { Activities, @@ -308,6 +310,10 @@ export class DataService { return this.http.delete(`/api/v1/user`, { body: aData }); } + public deleteTag(aId: string) { + return this.http.delete(`/api/v1/tags/${aId}`); + } + public deleteUser(aId: string) { return this.http.delete(`/api/v1/user/${aId}`); } @@ -662,6 +668,10 @@ export class DataService { ); } + public fetchTags() { + return this.http.get('/api/v1/tags'); + } + public loginAnonymous(accessToken: string) { return this.http.post('/api/v1/auth/anonymous', { accessToken @@ -709,6 +719,10 @@ export class DataService { return this.http.post('/api/v1/order', aOrder); } + public postTag(aTag: CreateTagDto) { + return this.http.post(`/api/v1/tags`, aTag); + } + public postUser() { return this.http.post('/api/v1/user', {}); } @@ -736,6 +750,10 @@ export class DataService { return this.http.put(`/api/v1/order/${aOrder.id}`, aOrder); } + public putTag(aTag: UpdateTagDto) { + return this.http.put(`/api/v1/tags/${aTag.id}`, aTag); + } + public putUserSetting(aData: UpdateUserSettingDto) { return this.http.put('/api/v1/user/setting', aData); } From b8c6a73f30bea84a120144eaf2c388250e91fe62 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 10:41:15 +0100 Subject: [PATCH 09/71] Feature/update locales 20250215 (#4314) * Update translation --------- Co-authored-by: github-actions[bot] Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- apps/client/src/locales/messages.ca.xlf | 14 +++++++++++--- apps/client/src/locales/messages.de.xlf | 14 +++++++++++--- apps/client/src/locales/messages.es.xlf | 14 +++++++++++--- apps/client/src/locales/messages.fr.xlf | 14 +++++++++++--- apps/client/src/locales/messages.it.xlf | 14 +++++++++++--- apps/client/src/locales/messages.nl.xlf | 14 +++++++++++--- apps/client/src/locales/messages.pl.xlf | 14 +++++++++++--- apps/client/src/locales/messages.pt.xlf | 14 +++++++++++--- apps/client/src/locales/messages.tr.xlf | 14 +++++++++++--- apps/client/src/locales/messages.uk.xlf | 14 +++++++++++--- apps/client/src/locales/messages.xlf | 13 ++++++++++--- apps/client/src/locales/messages.zh.xlf | 14 +++++++++++--- 12 files changed, 131 insertions(+), 36 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 82f3f96bb..d70c773e6 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -1787,7 +1787,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -2239,7 +2239,7 @@ Està segur que vol eliminar aquesta etiqueta? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -2639,7 +2639,7 @@ Informar d’un Problema amb les Dades apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 0040f8cb6..b7ff00641 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -1370,7 +1370,7 @@ Datenfehler melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -3370,7 +3370,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5891,7 +5891,7 @@ Möchtest du diesen Tag wirklich löschen? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Marktdaten + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index bc6a62411..e12415868 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -1371,7 +1371,7 @@ Reporta un anomalía de los datos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -3371,7 +3371,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5892,7 +5892,7 @@ Do you really want to delete this tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7757,6 +7757,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 353a2a3f6..bc5d94438 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1718,7 +1718,7 @@ Signaler une Erreur de Données apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -2598,7 +2598,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5891,7 +5891,7 @@ Confirmez la suppression de ce tag ? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index c6cb7ac7a..f6761f2c7 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -1371,7 +1371,7 @@ Segnala un’anomalia dei dati apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -3371,7 +3371,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5892,7 +5892,7 @@ Sei sicuro di voler eliminare questo tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7757,6 +7757,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 53efeab95..aab3a3939 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -1370,7 +1370,7 @@ Gegevensstoring melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -3370,7 +3370,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5891,7 +5891,7 @@ Do you really want to delete this tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 2942a4898..e2e157e14 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -1639,7 +1639,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -2067,7 +2067,7 @@ Czy naprawdę chcesz usunąć ten tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -2803,7 +2803,7 @@ Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 8b9b7ac03..69af89c1b 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -1678,7 +1678,7 @@ Dados do Relatório com Problema apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -3378,7 +3378,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5891,7 +5891,7 @@ Do you really want to delete this tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 3c7d3f102..c1e9963f7 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -2647,7 +2647,7 @@ Rapor Veri Sorunu apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -3955,7 +3955,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -5891,7 +5891,7 @@ Bu etiketi silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index 26690077b..f582408b7 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -2363,7 +2363,7 @@ Ви дійсно хочете видалити цей тег? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -2767,7 +2767,7 @@ Повідомити про збій даних apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -5139,7 +5139,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -7756,6 +7756,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index ac05bc01a..eba1176e5 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -1569,7 +1569,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -1962,7 +1962,7 @@ Do you really want to delete this tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -2623,7 +2623,7 @@ Report Data Glitch apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -7014,6 +7014,13 @@ 50 + + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 680906979..16e86c2f2 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -1648,7 +1648,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 70 + 71 @@ -2084,7 +2084,7 @@ 您真的要删除此标签吗? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 87 + 85 @@ -2820,7 +2820,7 @@ 报告数据故障 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 385 + 409 @@ -7757,6 +7757,14 @@ 50 + + Market Data + Market Data + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 374 + + From ab9133fa2478128f32472e0d3fdf267c14594762 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 15 Feb 2025 10:53:06 +0100 Subject: [PATCH 10/71] Bugfix/fix gaps in chart of benchmark comparator (#4311) * Fix benchmark interval * Update changelog --- CHANGELOG.md | 4 ++ .../src/app/benchmark/benchmark.controller.ts | 30 ++++++++- .../api/src/app/benchmark/benchmark.module.ts | 30 ++++++++- .../src/app/benchmark/benchmark.service.ts | 63 ++++++++++--------- .../analysis/analysis-page.component.ts | 1 + apps/client/src/app/services/data.service.ts | 14 +++-- 6 files changed, 102 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5e982369..4a24fb605 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for German (`de`) - Upgraded `@trivago/prettier-plugin-sort-imports` from version `5.2.1` to `5.2.2` +### Fixed + +- Fixed the gaps in the chart of the benchmark comparator + ## 2.138.0 - 2025-02-08 ### Added diff --git a/apps/api/src/app/benchmark/benchmark.controller.ts b/apps/api/src/app/benchmark/benchmark.controller.ts index 66c268b9b..d19081011 100644 --- a/apps/api/src/app/benchmark/benchmark.controller.ts +++ b/apps/api/src/app/benchmark/benchmark.controller.ts @@ -2,7 +2,9 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; +import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; +import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; import type { AssetProfileIdentifier, BenchmarkMarketDataDetails, @@ -16,6 +18,7 @@ import { Controller, Delete, Get, + Headers, HttpException, Inject, Param, @@ -34,6 +37,7 @@ import { BenchmarkService } from './benchmark.service'; @Controller('benchmark') export class BenchmarkController { public constructor( + private readonly apiService: ApiService, private readonly benchmarkService: BenchmarkService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @@ -108,23 +112,43 @@ export class BenchmarkController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getBenchmarkMarketDataForUser( + @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Param('dataSource') dataSource: DataSource, @Param('startDateString') startDateString: string, @Param('symbol') symbol: string, - @Query('range') dateRange: DateRange = 'max' + @Query('range') dateRange: DateRange = 'max', + @Query('accounts') filterByAccounts?: string, + @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, + @Query('symbol') filterBySymbol?: string, + @Query('tags') filterByTags?: string, + @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' ): Promise { const { endDate, startDate } = getIntervalFromDateRange( dateRange, new Date(startDateString) ); - const userCurrency = this.request.user.Settings.settings.baseCurrency; + + const filters = this.apiService.buildFiltersFromQueryParams({ + filterByAccounts, + filterByAssetClasses, + filterByDataSource, + filterBySymbol, + filterByTags + }); + + const withExcludedAccounts = withExcludedAccountsParam === 'true'; return this.benchmarkService.getMarketDataForUser({ dataSource, + dateRange, endDate, + filters, + impersonationId, startDate, symbol, - userCurrency + withExcludedAccounts, + user: this.request.user }); } } diff --git a/apps/api/src/app/benchmark/benchmark.module.ts b/apps/api/src/app/benchmark/benchmark.module.ts index 4c5f4d58e..8c0428729 100644 --- a/apps/api/src/app/benchmark/benchmark.module.ts +++ b/apps/api/src/app/benchmark/benchmark.module.ts @@ -1,13 +1,25 @@ +import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; +import { AccountService } from '@ghostfolio/api/app/account/account.service'; +import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; +import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; +import { RulesService } from '@ghostfolio/api/app/portfolio/rules.service'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module'; +import { UserModule } from '@ghostfolio/api/app/user/user.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 { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; +import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; +import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; +import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; @@ -19,18 +31,32 @@ import { BenchmarkService } from './benchmark.service'; controllers: [BenchmarkController], exports: [BenchmarkService], imports: [ + ApiModule, ConfigurationModule, DataProviderModule, ExchangeRateDataModule, + ImpersonationModule, MarketDataModule, + OrderModule, + PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, RedisCacheModule, SymbolModule, SymbolProfileModule, TransformDataSourceInRequestModule, - TransformDataSourceInResponseModule + TransformDataSourceInResponseModule, + UserModule ], - providers: [BenchmarkService] + providers: [ + AccountBalanceService, + AccountService, + BenchmarkService, + CurrentRateService, + MarketDataService, + PortfolioCalculatorFactory, + PortfolioService, + RulesService + ] }) export class BenchmarkModule {} diff --git a/apps/api/src/app/benchmark/benchmark.service.ts b/apps/api/src/app/benchmark/benchmark.service.ts index 4e466668c..3efbc74ff 100644 --- a/apps/api/src/app/benchmark/benchmark.service.ts +++ b/apps/api/src/app/benchmark/benchmark.service.ts @@ -1,6 +1,6 @@ +import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; @@ -22,22 +22,19 @@ import { Benchmark, BenchmarkMarketDataDetails, BenchmarkProperty, - BenchmarkResponse + BenchmarkResponse, + Filter } from '@ghostfolio/common/interfaces'; -import { BenchmarkTrend } from '@ghostfolio/common/types'; +import { + BenchmarkTrend, + DateRange, + UserWithSettings +} from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { SymbolProfile } from '@prisma/client'; import { Big } from 'big.js'; -import { - addHours, - differenceInDays, - eachDayOfInterval, - format, - isAfter, - isSameDay, - subDays -} from 'date-fns'; +import { addHours, format, isAfter, isSameDay, subDays } from 'date-fns'; import { isNumber, uniqBy } from 'lodash'; import ms from 'ms'; @@ -48,11 +45,11 @@ export class BenchmarkService { private readonly CACHE_KEY_BENCHMARKS = 'BENCHMARKS'; public constructor( - private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, private readonly prismaService: PrismaService, + private readonly portfolioService: PortfolioService, private readonly propertyService: PropertyService, private readonly redisCacheService: RedisCacheService, private readonly symbolProfileService: SymbolProfileService, @@ -158,31 +155,33 @@ export class BenchmarkService { public async getMarketDataForUser({ dataSource, + dateRange, endDate = new Date(), + filters, + impersonationId, startDate, symbol, - userCurrency + user, + withExcludedAccounts }: { + dateRange: DateRange; endDate?: Date; + filters?: Filter[]; + impersonationId: string; startDate: Date; - userCurrency: string; + user: UserWithSettings; + withExcludedAccounts?: boolean; } & AssetProfileIdentifier): Promise { const marketData: { date: string; value: number }[] = []; - - const days = differenceInDays(endDate, startDate) + 1; - const dates = eachDayOfInterval( - { - start: startDate, - end: endDate - }, - { - step: Math.round( - days / - Math.min(days, this.configurationService.get('MAX_CHART_ITEMS')) - ) - } - ).map((date) => { - return resetHours(date); + const userCurrency = user.Settings.settings.baseCurrency; + const userId = user.id; + + const { chart } = await this.portfolioService.getPerformance({ + dateRange, + filters, + impersonationId, + userId, + withExcludedAccounts }); const [currentSymbolItem, marketDataItems] = await Promise.all([ @@ -200,7 +199,9 @@ export class BenchmarkService { dataSource, symbol, date: { - in: dates + in: chart.map(({ date }) => { + return resetHours(parseDate(date)); + }) } } }) diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index a9a189d1f..5eebb42ef 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -321,6 +321,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { .fetchBenchmarkForUser({ dataSource, symbol, + filters: this.userService.getFilters(), range: this.user?.settings?.dateRange, startDate: this.firstOrderDate }) diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 0da1275e6..6782644ee 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -338,17 +338,23 @@ export class DataService { public fetchBenchmarkForUser({ dataSource, + filters, range, startDate, - symbol + symbol, + withExcludedAccounts }: { + filters?: Filter[]; range: DateRange; startDate: Date; + withExcludedAccounts?: boolean; } & AssetProfileIdentifier): Observable { - let params = new HttpParams(); + let params = this.buildFiltersAsQueryParams({ filters }); - if (range) { - params = params.append('range', range); + params = params.append('range', range); + + if (withExcludedAccounts) { + params = params.append('withExcludedAccounts', withExcludedAccounts); } return this.http.get( From 239adc1045104053df33155836925f540b86905b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 15 Feb 2025 10:55:37 +0100 Subject: [PATCH 11/71] Release 2.139.0 (#4320) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a24fb605..4b5be634a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.139.0 - 2025-02-15 ### Added diff --git a/package-lock.json b/package-lock.json index e015f580e..430ab9fbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.138.0", + "version": "2.139.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.138.0", + "version": "2.139.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index e3043de16..587e88ca5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.138.0", + "version": "2.139.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From e26b015407b774a2dfc92e9db0d270258c56058b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:50:41 +0100 Subject: [PATCH 12/71] Bugfix/cannot register cron jobs (#4325) * Reorganize benchmark modules and move benchmarks endpoint --- apps/api/src/app/admin/admin.module.ts | 2 +- apps/api/src/app/admin/admin.service.ts | 2 +- apps/api/src/app/app.module.ts | 4 +- .../benchmarks/benchmarks.controller.ts} | 10 +- .../benchmarks/benchmarks.module.ts} | 11 +- .../benchmarks/benchmarks.service.ts | 163 +++++++++++++++++ apps/api/src/app/info/info.module.ts | 2 +- apps/api/src/app/info/info.service.ts | 2 +- .../services/benchmark/benchmark.module.ts | 24 +++ .../benchmark/benchmark.service.spec.ts | 12 +- .../benchmark/benchmark.service.ts | 165 +----------------- .../interfaces/benchmark-value.interface.ts | 0 .../twitter-bot/twitter-bot.module.ts | 2 +- .../twitter-bot/twitter-bot.service.ts | 2 +- apps/client/src/app/services/data.service.ts | 8 +- 15 files changed, 218 insertions(+), 191 deletions(-) rename apps/api/src/app/{benchmark/benchmark.controller.ts => endpoints/benchmarks/benchmarks.controller.ts} (93%) rename apps/api/src/app/{benchmark/benchmark.module.ts => endpoints/benchmarks/benchmarks.module.ts} (90%) create mode 100644 apps/api/src/app/endpoints/benchmarks/benchmarks.service.ts create mode 100644 apps/api/src/services/benchmark/benchmark.module.ts rename apps/api/src/{app => services}/benchmark/benchmark.service.spec.ts (74%) rename apps/api/src/{app => services}/benchmark/benchmark.service.ts (65%) rename apps/api/src/{app => services}/benchmark/interfaces/benchmark-value.interface.ts (100%) diff --git a/apps/api/src/app/admin/admin.module.ts b/apps/api/src/app/admin/admin.module.ts index 81c58ff03..d94cdd963 100644 --- a/apps/api/src/app/admin/admin.module.ts +++ b/apps/api/src/app/admin/admin.module.ts @@ -1,8 +1,8 @@ -import { BenchmarkModule } from '@ghostfolio/api/app/benchmark/benchmark.module'; import { OrderModule } from '@ghostfolio/api/app/order/order.module'; import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; +import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index fb6e90f5d..142109725 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -1,7 +1,7 @@ -import { BenchmarkService } from '@ghostfolio/api/app/benchmark/benchmark.service'; import { OrderService } from '@ghostfolio/api/app/order/order.service'; import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service'; import { environment } from '@ghostfolio/api/environments/environment'; +import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 3e68bf428..2a515bf43 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -29,10 +29,10 @@ import { AppController } from './app.controller'; import { AssetModule } from './asset/asset.module'; import { AuthDeviceModule } from './auth-device/auth-device.module'; import { AuthModule } from './auth/auth.module'; -import { BenchmarkModule } from './benchmark/benchmark.module'; import { CacheModule } from './cache/cache.module'; import { AiModule } from './endpoints/ai/ai.module'; import { ApiKeysModule } from './endpoints/api-keys/api-keys.module'; +import { BenchmarksModule } from './endpoints/benchmarks/benchmarks.module'; import { GhostfolioModule } from './endpoints/data-providers/ghostfolio/ghostfolio.module'; import { MarketDataModule } from './endpoints/market-data/market-data.module'; import { PublicModule } from './endpoints/public/public.module'; @@ -63,7 +63,7 @@ import { UserModule } from './user/user.module'; AssetModule, AuthDeviceModule, AuthModule, - BenchmarkModule, + BenchmarksModule, BullModule.forRoot({ redis: { db: parseInt(process.env.REDIS_DB ?? '0', 10), diff --git a/apps/api/src/app/benchmark/benchmark.controller.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts similarity index 93% rename from apps/api/src/app/benchmark/benchmark.controller.ts rename to apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts index d19081011..69383a30d 100644 --- a/apps/api/src/app/benchmark/benchmark.controller.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts @@ -3,6 +3,7 @@ import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard' import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; +import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; import type { @@ -32,13 +33,14 @@ import { AuthGuard } from '@nestjs/passport'; import { DataSource } from '@prisma/client'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; -import { BenchmarkService } from './benchmark.service'; +import { BenchmarksService } from './benchmarks.service'; -@Controller('benchmark') -export class BenchmarkController { +@Controller('benchmarks') +export class BenchmarksController { public constructor( private readonly apiService: ApiService, private readonly benchmarkService: BenchmarkService, + private readonly benchmarksService: BenchmarksService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @@ -139,7 +141,7 @@ export class BenchmarkController { const withExcludedAccounts = withExcludedAccountsParam === 'true'; - return this.benchmarkService.getMarketDataForUser({ + return this.benchmarksService.getMarketDataForUser({ dataSource, dateRange, endDate, diff --git a/apps/api/src/app/benchmark/benchmark.module.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts similarity index 90% rename from apps/api/src/app/benchmark/benchmark.module.ts rename to apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts index 8c0428729..a0f443621 100644 --- a/apps/api/src/app/benchmark/benchmark.module.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts @@ -11,6 +11,7 @@ import { UserModule } from '@ghostfolio/api/app/user/user.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 { ApiModule } from '@ghostfolio/api/services/api/api.module'; +import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; @@ -24,12 +25,11 @@ import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/sym import { Module } from '@nestjs/common'; -import { BenchmarkController } from './benchmark.controller'; -import { BenchmarkService } from './benchmark.service'; +import { BenchmarksController } from './benchmarks.controller'; +import { BenchmarksService } from './benchmarks.service'; @Module({ - controllers: [BenchmarkController], - exports: [BenchmarkService], + controllers: [BenchmarksController], imports: [ ApiModule, ConfigurationModule, @@ -52,6 +52,7 @@ import { BenchmarkService } from './benchmark.service'; AccountBalanceService, AccountService, BenchmarkService, + BenchmarksService, CurrentRateService, MarketDataService, PortfolioCalculatorFactory, @@ -59,4 +60,4 @@ import { BenchmarkService } from './benchmark.service'; RulesService ] }) -export class BenchmarkModule {} +export class BenchmarksModule {} diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.service.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.service.ts new file mode 100644 index 000000000..237f0d153 --- /dev/null +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.service.ts @@ -0,0 +1,163 @@ +import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; +import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; +import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; +import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper'; +import { + AssetProfileIdentifier, + BenchmarkMarketDataDetails, + Filter +} from '@ghostfolio/common/interfaces'; +import { DateRange, UserWithSettings } from '@ghostfolio/common/types'; + +import { Injectable, Logger } from '@nestjs/common'; +import { format, isSameDay } from 'date-fns'; +import { isNumber } from 'lodash'; + +@Injectable() +export class BenchmarksService { + public constructor( + private readonly benchmarkService: BenchmarkService, + private readonly exchangeRateDataService: ExchangeRateDataService, + private readonly marketDataService: MarketDataService, + private readonly portfolioService: PortfolioService, + private readonly symbolService: SymbolService + ) {} + + public async getMarketDataForUser({ + dataSource, + dateRange, + endDate = new Date(), + filters, + impersonationId, + startDate, + symbol, + user, + withExcludedAccounts + }: { + dateRange: DateRange; + endDate?: Date; + filters?: Filter[]; + impersonationId: string; + startDate: Date; + user: UserWithSettings; + withExcludedAccounts?: boolean; + } & AssetProfileIdentifier): Promise { + const marketData: { date: string; value: number }[] = []; + const userCurrency = user.Settings.settings.baseCurrency; + const userId = user.id; + + const { chart } = await this.portfolioService.getPerformance({ + dateRange, + filters, + impersonationId, + userId, + withExcludedAccounts + }); + + const [currentSymbolItem, marketDataItems] = await Promise.all([ + this.symbolService.get({ + dataGatheringItem: { + dataSource, + symbol + } + }), + this.marketDataService.marketDataItems({ + orderBy: { + date: 'asc' + }, + where: { + dataSource, + symbol, + date: { + in: chart.map(({ date }) => { + return resetHours(parseDate(date)); + }) + } + } + }) + ]); + + const exchangeRates = + await this.exchangeRateDataService.getExchangeRatesByCurrency({ + startDate, + currencies: [currentSymbolItem.currency], + targetCurrency: userCurrency + }); + + const exchangeRateAtStartDate = + exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ + format(startDate, DATE_FORMAT) + ]; + + const marketPriceAtStartDate = marketDataItems?.find(({ date }) => { + return isSameDay(date, startDate); + })?.marketPrice; + + if (!marketPriceAtStartDate) { + Logger.error( + `No historical market data has been found for ${symbol} (${dataSource}) at ${format( + startDate, + DATE_FORMAT + )}`, + 'BenchmarkService' + ); + + return { marketData }; + } + + for (const marketDataItem of marketDataItems) { + const exchangeRate = + exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ + format(marketDataItem.date, DATE_FORMAT) + ]; + + const exchangeRateFactor = + isNumber(exchangeRateAtStartDate) && isNumber(exchangeRate) + ? exchangeRate / exchangeRateAtStartDate + : 1; + + marketData.push({ + date: format(marketDataItem.date, DATE_FORMAT), + value: + marketPriceAtStartDate === 0 + ? 0 + : this.benchmarkService.calculateChangeInPercentage( + marketPriceAtStartDate, + marketDataItem.marketPrice * exchangeRateFactor + ) * 100 + }); + } + + const includesEndDate = isSameDay( + parseDate(marketData.at(-1).date), + endDate + ); + + if (currentSymbolItem?.marketPrice && !includesEndDate) { + const exchangeRate = + exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ + format(endDate, DATE_FORMAT) + ]; + + const exchangeRateFactor = + isNumber(exchangeRateAtStartDate) && isNumber(exchangeRate) + ? exchangeRate / exchangeRateAtStartDate + : 1; + + marketData.push({ + date: format(endDate, DATE_FORMAT), + value: + this.benchmarkService.calculateChangeInPercentage( + marketPriceAtStartDate, + currentSymbolItem.marketPrice * exchangeRateFactor + ) * 100 + }); + } + + return { + marketData + }; + } +} diff --git a/apps/api/src/app/info/info.module.ts b/apps/api/src/app/info/info.module.ts index 7903ac397..d7a5ed641 100644 --- a/apps/api/src/app/info/info.module.ts +++ b/apps/api/src/app/info/info.module.ts @@ -1,8 +1,8 @@ -import { BenchmarkModule } from '@ghostfolio/api/app/benchmark/benchmark.module'; import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { UserModule } from '@ghostfolio/api/app/user/user.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; +import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 1af41520d..780860232 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -1,7 +1,7 @@ -import { BenchmarkService } from '@ghostfolio/api/app/benchmark/benchmark.service'; import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; +import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; diff --git a/apps/api/src/services/benchmark/benchmark.module.ts b/apps/api/src/services/benchmark/benchmark.module.ts new file mode 100644 index 000000000..870ef244f --- /dev/null +++ b/apps/api/src/services/benchmark/benchmark.module.ts @@ -0,0 +1,24 @@ +import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; +import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; +import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; +import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; +import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; + +import { Module } from '@nestjs/common'; + +import { BenchmarkService } from './benchmark.service'; + +@Module({ + exports: [BenchmarkService], + imports: [ + DataProviderModule, + MarketDataModule, + PrismaModule, + PropertyModule, + RedisCacheModule, + SymbolProfileModule + ], + providers: [BenchmarkService] +}) +export class BenchmarkModule {} diff --git a/apps/api/src/app/benchmark/benchmark.service.spec.ts b/apps/api/src/services/benchmark/benchmark.service.spec.ts similarity index 74% rename from apps/api/src/app/benchmark/benchmark.service.spec.ts rename to apps/api/src/services/benchmark/benchmark.service.spec.ts index 5371fcdc0..833dbcdfc 100644 --- a/apps/api/src/app/benchmark/benchmark.service.spec.ts +++ b/apps/api/src/services/benchmark/benchmark.service.spec.ts @@ -4,17 +4,7 @@ describe('BenchmarkService', () => { let benchmarkService: BenchmarkService; beforeAll(async () => { - benchmarkService = new BenchmarkService( - null, - null, - null, - null, - null, - null, - null, - null, - null - ); + benchmarkService = new BenchmarkService(null, null, null, null, null, null); }); it('calculateChangeInPercentage', async () => { diff --git a/apps/api/src/app/benchmark/benchmark.service.ts b/apps/api/src/services/benchmark/benchmark.service.ts similarity index 65% rename from apps/api/src/app/benchmark/benchmark.service.ts rename to apps/api/src/services/benchmark/benchmark.service.ts index 3efbc74ff..57105da71 100644 --- a/apps/api/src/app/benchmark/benchmark.service.ts +++ b/apps/api/src/services/benchmark/benchmark.service.ts @@ -1,8 +1,5 @@ -import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; -import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; -import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; @@ -11,31 +8,20 @@ import { CACHE_TTL_INFINITE, PROPERTY_BENCHMARKS } from '@ghostfolio/common/config'; -import { - DATE_FORMAT, - calculateBenchmarkTrend, - parseDate, - resetHours -} from '@ghostfolio/common/helper'; +import { calculateBenchmarkTrend } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, Benchmark, - BenchmarkMarketDataDetails, BenchmarkProperty, - BenchmarkResponse, - Filter + BenchmarkResponse } from '@ghostfolio/common/interfaces'; -import { - BenchmarkTrend, - DateRange, - UserWithSettings -} from '@ghostfolio/common/types'; +import { BenchmarkTrend } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { SymbolProfile } from '@prisma/client'; import { Big } from 'big.js'; -import { addHours, format, isAfter, isSameDay, subDays } from 'date-fns'; -import { isNumber, uniqBy } from 'lodash'; +import { addHours, isAfter, subDays } from 'date-fns'; +import { uniqBy } from 'lodash'; import ms from 'ms'; import { BenchmarkValue } from './interfaces/benchmark-value.interface'; @@ -46,14 +32,11 @@ export class BenchmarkService { public constructor( private readonly dataProviderService: DataProviderService, - private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, private readonly prismaService: PrismaService, - private readonly portfolioService: PortfolioService, private readonly propertyService: PropertyService, private readonly redisCacheService: RedisCacheService, - private readonly symbolProfileService: SymbolProfileService, - private readonly symbolService: SymbolService + private readonly symbolProfileService: SymbolProfileService ) {} public calculateChangeInPercentage(baseValue: number, currentValue: number) { @@ -153,142 +136,6 @@ export class BenchmarkService { .sort((a, b) => a.name.localeCompare(b.name)); } - public async getMarketDataForUser({ - dataSource, - dateRange, - endDate = new Date(), - filters, - impersonationId, - startDate, - symbol, - user, - withExcludedAccounts - }: { - dateRange: DateRange; - endDate?: Date; - filters?: Filter[]; - impersonationId: string; - startDate: Date; - user: UserWithSettings; - withExcludedAccounts?: boolean; - } & AssetProfileIdentifier): Promise { - const marketData: { date: string; value: number }[] = []; - const userCurrency = user.Settings.settings.baseCurrency; - const userId = user.id; - - const { chart } = await this.portfolioService.getPerformance({ - dateRange, - filters, - impersonationId, - userId, - withExcludedAccounts - }); - - const [currentSymbolItem, marketDataItems] = await Promise.all([ - this.symbolService.get({ - dataGatheringItem: { - dataSource, - symbol - } - }), - this.marketDataService.marketDataItems({ - orderBy: { - date: 'asc' - }, - where: { - dataSource, - symbol, - date: { - in: chart.map(({ date }) => { - return resetHours(parseDate(date)); - }) - } - } - }) - ]); - - const exchangeRates = - await this.exchangeRateDataService.getExchangeRatesByCurrency({ - startDate, - currencies: [currentSymbolItem.currency], - targetCurrency: userCurrency - }); - - const exchangeRateAtStartDate = - exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ - format(startDate, DATE_FORMAT) - ]; - - const marketPriceAtStartDate = marketDataItems?.find(({ date }) => { - return isSameDay(date, startDate); - })?.marketPrice; - - if (!marketPriceAtStartDate) { - Logger.error( - `No historical market data has been found for ${symbol} (${dataSource}) at ${format( - startDate, - DATE_FORMAT - )}`, - 'BenchmarkService' - ); - - return { marketData }; - } - - for (const marketDataItem of marketDataItems) { - const exchangeRate = - exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ - format(marketDataItem.date, DATE_FORMAT) - ]; - - const exchangeRateFactor = - isNumber(exchangeRateAtStartDate) && isNumber(exchangeRate) - ? exchangeRate / exchangeRateAtStartDate - : 1; - - marketData.push({ - date: format(marketDataItem.date, DATE_FORMAT), - value: - marketPriceAtStartDate === 0 - ? 0 - : this.calculateChangeInPercentage( - marketPriceAtStartDate, - marketDataItem.marketPrice * exchangeRateFactor - ) * 100 - }); - } - - const includesEndDate = isSameDay( - parseDate(marketData.at(-1).date), - endDate - ); - - if (currentSymbolItem?.marketPrice && !includesEndDate) { - const exchangeRate = - exchangeRates[`${currentSymbolItem.currency}${userCurrency}`]?.[ - format(endDate, DATE_FORMAT) - ]; - - const exchangeRateFactor = - isNumber(exchangeRateAtStartDate) && isNumber(exchangeRate) - ? exchangeRate / exchangeRateAtStartDate - : 1; - - marketData.push({ - date: format(endDate, DATE_FORMAT), - value: - this.calculateChangeInPercentage( - marketPriceAtStartDate, - currentSymbolItem.marketPrice * exchangeRateFactor - ) * 100 - }); - } - - return { - marketData - }; - } - public async addBenchmark({ dataSource, symbol diff --git a/apps/api/src/app/benchmark/interfaces/benchmark-value.interface.ts b/apps/api/src/services/benchmark/interfaces/benchmark-value.interface.ts similarity index 100% rename from apps/api/src/app/benchmark/interfaces/benchmark-value.interface.ts rename to apps/api/src/services/benchmark/interfaces/benchmark-value.interface.ts diff --git a/apps/api/src/services/twitter-bot/twitter-bot.module.ts b/apps/api/src/services/twitter-bot/twitter-bot.module.ts index 4a2b1589a..80d53169c 100644 --- a/apps/api/src/services/twitter-bot/twitter-bot.module.ts +++ b/apps/api/src/services/twitter-bot/twitter-bot.module.ts @@ -1,5 +1,5 @@ -import { BenchmarkModule } from '@ghostfolio/api/app/benchmark/benchmark.module'; import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module'; +import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { TwitterBotService } from '@ghostfolio/api/services/twitter-bot/twitter-bot.service'; diff --git a/apps/api/src/services/twitter-bot/twitter-bot.service.ts b/apps/api/src/services/twitter-bot/twitter-bot.service.ts index a32882aed..a17585c5b 100644 --- a/apps/api/src/services/twitter-bot/twitter-bot.service.ts +++ b/apps/api/src/services/twitter-bot/twitter-bot.service.ts @@ -1,5 +1,5 @@ -import { BenchmarkService } from '@ghostfolio/api/app/benchmark/benchmark.service'; import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; +import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ghostfolioFearAndGreedIndexDataSource, diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 6782644ee..0bc4ebccc 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -303,7 +303,7 @@ export class DataService { } public deleteBenchmark({ dataSource, symbol }: AssetProfileIdentifier) { - return this.http.delete(`/api/v1/benchmark/${dataSource}/${symbol}`); + return this.http.delete(`/api/v1/benchmarks/${dataSource}/${symbol}`); } public deleteOwnUser(aData: DeleteOwnUserDto) { @@ -358,7 +358,7 @@ export class DataService { } return this.http.get( - `/api/v1/benchmark/${dataSource}/${symbol}/${format( + `/api/v1/benchmarks/${dataSource}/${symbol}/${format( startDate, DATE_FORMAT )}`, @@ -367,7 +367,7 @@ export class DataService { } public fetchBenchmarks() { - return this.http.get('/api/v1/benchmark'); + return this.http.get('/api/v1/benchmarks'); } public fetchExport({ @@ -704,7 +704,7 @@ export class DataService { } public postBenchmark(benchmark: AssetProfileIdentifier) { - return this.http.post('/api/v1/benchmark', benchmark); + return this.http.post('/api/v1/benchmarks', benchmark); } public postMarketData({ From 57673046e7d14c5fbaf9ec8b31aea90719a38972 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:52:25 +0100 Subject: [PATCH 13/71] Release 2.139.1 (#4326) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b5be634a..ac0f572de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.139.0 - 2025-02-15 +## 2.139.1 - 2025-02-15 ### Added diff --git a/package-lock.json b/package-lock.json index 430ab9fbb..21cc622d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.139.0", + "version": "2.139.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.139.0", + "version": "2.139.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 587e88ca5..a97178081 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.139.0", + "version": "2.139.1", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 02a4e270836ffb54d0f9aa0a3751e119e1dbec82 Mon Sep 17 00:00:00 2001 From: Ken Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 16 Feb 2025 14:47:44 +0700 Subject: [PATCH 14/71] Bugfix/missing assets in Storybook (#4324) * fix(sb): add staticDirs config * fix(sb): improve config type safety * Update changelog --- CHANGELOG.md | 6 ++++++ libs/ui/.storybook/main.js | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0f572de..9c26756aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Added missing assets in _Storybook_ setup + ## 2.139.1 - 2025-02-15 ### Added diff --git a/libs/ui/.storybook/main.js b/libs/ui/.storybook/main.js index 8c8323a0c..5b50ae062 100644 --- a/libs/ui/.storybook/main.js +++ b/libs/ui/.storybook/main.js @@ -1,9 +1,16 @@ +/** @type {import('@storybook/angular').StorybookConfig} */ const config = { addons: ['@storybook/addon-essentials'], framework: { name: '@storybook/angular', options: {} }, + staticDirs: [ + { + from: '../../../apps/client/src/assets', + to: '/assets' + } + ], stories: ['../**/*.stories.@(js|jsx|ts|tsx|mdx)'] }; From ec098c8d68353b56de99a53e9920dc7a8e21c889 Mon Sep 17 00:00:00 2001 From: Ken Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Tue, 18 Feb 2025 01:21:08 +0700 Subject: [PATCH 15/71] Feature/extend tooltip of treemap chart (#4323) * feat(ui): Extend tooltip * allocation * change * performance * feat(sb): add story for treemap chart * Update changelog --- CHANGELOG.md | 1 + .../treemap-chart.component.stories.ts | 392 ++++++++++++++++++ .../treemap-chart/treemap-chart.component.ts | 30 +- 3 files changed, 417 insertions(+), 6 deletions(-) create mode 100644 libs/ui/src/lib/treemap-chart/treemap-chart.component.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c26756aa..cfd358244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Extended the tooltip in the chart of the holdings tab on the home page by the allocation, change and performance - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Asia-Pacific Markets) - Added a new static portfolio analysis rule: _Regional Market Cluster Risk_ (Japan) - Added support to create custom tags in the holding detail dialog (experimental) diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.stories.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.stories.ts new file mode 100644 index 000000000..2000b4f98 --- /dev/null +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.stories.ts @@ -0,0 +1,392 @@ +import { CommonModule } from '@angular/common'; +import '@angular/localize/init'; +import { moduleMetadata } from '@storybook/angular'; +import type { Meta, StoryObj } from '@storybook/angular'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + +import { GfTreemapChartComponent } from './treemap-chart.component'; + +export default { + title: 'Treemap Chart', + component: GfTreemapChartComponent, + decorators: [ + moduleMetadata({ + imports: [CommonModule, NgxSkeletonLoaderModule] + }) + ], + argTypes: { + colorScheme: { + control: { + type: 'select' + }, + options: ['DARK', 'LIGHT'] + }, + cursor: { + control: { + type: 'select' + }, + options: ['', 'pointer'] + } + } +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + baseCurrency: 'USD', + colorScheme: 'LIGHT', + cursor: undefined, + dateRange: 'mtd', + holdings: [ + { + allocationInPercentage: 0.042990776363386086, + assetClass: 'EQUITY', + assetSubClass: 'STOCK', + countries: [], + currency: 'USD', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2021-12-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 3856, + grossPerformancePercent: 0.46047289228564603, + grossPerformancePercentWithCurrencyEffect: 0.46047289228564603, + grossPerformanceWithCurrencyEffect: 3856, + holdings: [], + investment: 8374, + marketPrice: 244.6, + name: 'Apple Inc', + netPerformance: 3855, + netPerformancePercent: 0.460353475041796, + netPerformancePercentWithCurrencyEffect: 0.036440677966101696, + netPerformanceWithCurrencyEffect: 430, + quantity: 50, + sectors: [], + symbol: 'AAPL', + tags: [], + transactionCount: 1, + url: 'https://www.apple.com', + valueInBaseCurrency: 12230 + }, + { + allocationInPercentage: 0.02377401948293552, + assetClass: 'EQUITY', + assetSubClass: 'STOCK', + countries: [], + currency: 'EUR', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2021-04-23T00:00:00.000Z'), + dividend: 192, + grossPerformance: 2226.700251889169, + grossPerformancePercent: 0.49083842309827874, + grossPerformancePercentWithCurrencyEffect: 0.29306136948826367, + grossPerformanceWithCurrencyEffect: 1532.8272791336772, + holdings: [], + investment: 4536.523929471033, + marketPrice: 322.2, + name: 'Allianz SE', + netPerformance: 2222.2921914357685, + netPerformancePercent: 0.48986674069961134, + netPerformancePercentWithCurrencyEffect: 0.034489367670592026, + netPerformanceWithCurrencyEffect: 225.48257403052068, + quantity: 20, + sectors: [], + symbol: 'ALV.DE', + tags: [], + transactionCount: 2, + url: 'https://www.allianz.com', + valueInBaseCurrency: 6763.224181360202 + }, + { + allocationInPercentage: 0.08038536990007467, + assetClass: 'EQUITY', + assetSubClass: 'STOCK', + countries: [], + currency: 'USD', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2018-10-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 12758.05, + grossPerformancePercent: 1.2619300787837724, + grossPerformancePercentWithCurrencyEffect: 1.2619300787837724, + grossPerformanceWithCurrencyEffect: 12758.05, + holdings: [], + investment: 10109.95, + marketPrice: 228.68, + name: 'Amazon.com, Inc.', + netPerformance: 12677.26, + netPerformancePercent: 1.253938941339967, + netPerformancePercentWithCurrencyEffect: -0.037866008722316276, + netPerformanceWithCurrencyEffect: -899.99926757812, + quantity: 100, + sectors: [], + symbol: 'AMZN', + tags: [], + transactionCount: 1, + url: 'https://www.aboutamazon.com', + valueInBaseCurrency: 22868 + }, + { + allocationInPercentage: 0.19216416482928922, + assetClass: 'LIQUIDITY', + assetSubClass: 'CRYPTOCURRENCY', + countries: [], + currency: 'USD', + dataSource: 'COINGECKO', + dateOfFirstActivity: new Date('2017-08-16T00:00:00.000Z'), + dividend: 0, + grossPerformance: 52666.7898248, + grossPerformancePercent: 26.333394912400003, + grossPerformancePercentWithCurrencyEffect: 26.333394912400003, + grossPerformanceWithCurrencyEffect: 52666.7898248, + holdings: [], + investment: 1999.9999999999998, + marketPrice: 97364, + name: 'Bitcoin', + netPerformance: 52636.8898248, + netPerformancePercent: 26.3184449124, + netPerformancePercentWithCurrencyEffect: -0.04760906442310894, + netPerformanceWithCurrencyEffect: -2732.737808972287, + quantity: 0.5614682, + sectors: [], + symbol: 'bitcoin', + tags: [], + transactionCount: 1, + url: null, + valueInBaseCurrency: 54666.7898248 + }, + { + allocationInPercentage: 0.007378652850073097, + assetClass: 'FIXED_INCOME', + assetSubClass: 'BOND', + countries: [], + currency: 'EUR', + dataSource: 'MANUAL', + dateOfFirstActivity: new Date('2021-02-01T00:00:00.000Z'), + dividend: 11.45, + grossPerformance: 0, + grossPerformancePercent: 0, + grossPerformancePercentWithCurrencyEffect: -0.1247202380342517, + grossPerformanceWithCurrencyEffect: -258.2576430160448, + holdings: [], + investment: 2099.0764063811926, + marketPrice: 1, + name: 'Bondora Go & Grow', + netPerformance: 0, + netPerformancePercent: 0, + netPerformancePercentWithCurrencyEffect: 0.009445843828715519, + netPerformanceWithCurrencyEffect: 19.6420125363184, + quantity: 2000, + sectors: [], + symbol: 'BONDORA_GO_AND_GROW', + tags: [], + transactionCount: 5, + url: null, + valueInBaseCurrency: 2099.0764063811926 + }, + { + allocationInPercentage: 0.07787531695543741, + assetClass: 'EQUITY', + assetSubClass: 'ETF', + countries: [], + currency: 'CHF', + dataSource: 'MANUAL', + dateOfFirstActivity: new Date('2021-04-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 4550.843985045582, + grossPerformancePercent: 0.3631417324494093, + grossPerformancePercentWithCurrencyEffect: 0.42037247857285137, + grossPerformanceWithCurrencyEffect: 5107.057936556927, + holdings: [], + investment: 17603.097090932337, + marketPrice: 188.22, + name: 'frankly Extreme 95 Index', + netPerformance: 4550.843985045582, + netPerformancePercent: 0.3631417324494093, + netPerformancePercentWithCurrencyEffect: 0.026190604904358043, + netPerformanceWithCurrencyEffect: 565.4165171873152, + quantity: 105.87328656807, + sectors: [], + symbol: 'FRANKLY95P', + tags: [], + transactionCount: 6, + url: 'https://www.frankly.ch', + valueInBaseCurrency: 22153.941075977917 + }, + { + allocationInPercentage: 0.04307127421937313, + assetClass: 'EQUITY', + assetSubClass: 'STOCK', + countries: [], + currency: 'USD', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2023-01-03T00:00:00.000Z'), + dividend: 0, + grossPerformance: 5065.5, + grossPerformancePercent: 0.7047750229568411, + grossPerformancePercentWithCurrencyEffect: 0.7047750229568411, + grossPerformanceWithCurrencyEffect: 5065.5, + holdings: [], + investment: 7187.4, + marketPrice: 408.43, + name: 'Microsoft Corporation', + netPerformance: 5065.5, + netPerformancePercent: 0.7047750229568411, + netPerformancePercentWithCurrencyEffect: -0.015973588391056275, + netPerformanceWithCurrencyEffect: -198.899926757814, + quantity: 30, + sectors: [], + symbol: 'MSFT', + tags: [], + transactionCount: 1, + url: 'https://www.microsoft.com', + valueInBaseCurrency: 12252.9 + }, + { + allocationInPercentage: 0.18762679306394897, + assetClass: 'EQUITY', + assetSubClass: 'STOCK', + countries: [], + currency: 'USD', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2017-01-03T00:00:00.000Z'), + dividend: 0, + grossPerformance: 51227.500000005, + grossPerformancePercent: 23.843379101756675, + grossPerformancePercentWithCurrencyEffect: 23.843379101756675, + grossPerformanceWithCurrencyEffect: 51227.500000005, + holdings: [], + investment: 2148.499999995, + marketPrice: 355.84, + name: 'Tesla, Inc.', + netPerformance: 51197.500000005, + netPerformancePercent: 23.829415871596066, + netPerformancePercentWithCurrencyEffect: -0.12051410125545206, + netPerformanceWithCurrencyEffect: -7314.00091552734, + quantity: 150, + sectors: [], + symbol: 'TSLA', + tags: [], + transactionCount: 1, + url: 'https://www.tesla.com', + valueInBaseCurrency: 53376 + }, + { + allocationInPercentage: 0.053051250766657634, + assetClass: 'EQUITY', + assetSubClass: 'ETF', + countries: [], + currency: 'USD', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2019-03-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 6845.8, + grossPerformancePercent: 1.0164758094605268, + grossPerformancePercentWithCurrencyEffect: 1.0164758094605268, + grossPerformanceWithCurrencyEffect: 6845.8, + holdings: [], + investment: 8246.2, + marketPrice: 301.84, + name: 'Vanguard Total Stock Market Index Fund ETF Shares', + netPerformance: 6746.3, + netPerformancePercent: 1.0017018833976383, + netPerformancePercentWithCurrencyEffect: 0.01085061564051406, + netPerformanceWithCurrencyEffect: 161.99969482422, + quantity: 50, + sectors: [], + symbol: 'VTI', + tags: [], + transactionCount: 5, + url: 'https://www.vanguard.com', + valueInBaseCurrency: 15092 + }, + { + allocationInPercentage: 0.0836576192450555, + assetClass: 'EQUITY', + assetSubClass: 'ETF', + countries: [], + currency: 'CHF', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2018-03-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 6462.42356864925, + grossPerformancePercent: 0.5463044783973836, + grossPerformancePercentWithCurrencyEffect: 0.6282343505275325, + grossPerformanceWithCurrencyEffect: 7121.935580698947, + holdings: [], + investment: 17336.464702612564, + marketPrice: 129.74, + name: 'Vanguard FTSE All-World UCITS ETF', + netPerformance: 6373.040578098944, + netPerformancePercent: 0.5387484388540966, + netPerformancePercentWithCurrencyEffect: 0.008409682389650015, + netPerformanceWithCurrencyEffect: 198.47200506226807, + quantity: 165, + sectors: [], + symbol: 'VWRL.SW', + tags: [], + transactionCount: 5, + url: 'https://www.vanguard.com', + valueInBaseCurrency: 23798.888271261814 + }, + { + allocationInPercentage: 0.03265192235898284, + assetClass: 'EQUITY', + assetSubClass: 'ETF', + countries: [], + currency: 'EUR', + dataSource: 'YAHOO', + dateOfFirstActivity: new Date('2021-08-19T00:00:00.000Z'), + dividend: 0, + grossPerformance: 3112.7991183879094, + grossPerformancePercent: 0.5040147846036197, + grossPerformancePercentWithCurrencyEffect: 0.3516875105542396, + grossPerformanceWithCurrencyEffect: 2416.799201046856, + holdings: [], + investment: 6176.007556675063, + marketPrice: 118.005, + name: 'Xtrackers MSCI World UCITS ETF 1C', + netPerformance: 3081.4179261125105, + netPerformancePercent: 0.4989336392216841, + netPerformancePercentWithCurrencyEffect: 0.006460676966633529, + netPerformanceWithCurrencyEffect: 59.626750161726044, + quantity: 75, + sectors: [], + symbol: 'XDWD.DE', + tags: [], + transactionCount: 1, + url: null, + valueInBaseCurrency: 9288.806675062973 + }, + { + allocationInPercentage: 0.17537283996478595, + assetClass: 'LIQUIDITY', + assetSubClass: 'CASH', + countries: [], + currency: 'USD', + dataSource: 'MANUAL', + dateOfFirstActivity: new Date('2021-04-01T00:00:00.000Z'), + dividend: 0, + grossPerformance: 0, + grossPerformancePercent: 0, + grossPerformancePercentWithCurrencyEffect: 0, + grossPerformanceWithCurrencyEffect: 0, + holdings: [], + investment: 49890, + marketPrice: 0, + name: 'USD', + netPerformance: 0, + netPerformancePercent: 0, + netPerformancePercentWithCurrencyEffect: 0, + netPerformanceWithCurrencyEffect: 0, + quantity: 0, + sectors: [], + symbol: 'USD', + tags: [], + transactionCount: 0, + valueInBaseCurrency: 49890 + } + ], + locale: 'en-US' + } +}; diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts index 4c3167c9e..8c5ee94de 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -342,24 +342,42 @@ export class GfTreemapChartComponent }), callbacks: { label: (context) => { + const allocationInPercentage = `${((context.raw._data.allocationInPercentage as number) * 100).toFixed(2)}%`; const name = context.raw._data.name; + const sign = + context.raw._data.netPerformancePercentWithCurrencyEffect > 0 + ? '+' + : ''; const symbol = context.raw._data.symbol; + const netPerformanceInPercentageWithSign = `${sign}${(context.raw._data.netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%`; + if (context.raw._data.valueInBaseCurrency !== null) { const value = context.raw._data.valueInBaseCurrency as number; return [ - `${name ?? symbol}`, + `${name ?? symbol} (${allocationInPercentage})`, `${value.toLocaleString(this.locale, { maximumFractionDigits: 2, minimumFractionDigits: 2 - })} ${this.baseCurrency}` + })} ${this.baseCurrency}`, + '', + $localize`Change` + ' (' + $localize`Performance` + ')', + `${sign}${context.raw._data.netPerformanceWithCurrencyEffect.toLocaleString( + this.locale, + { + maximumFractionDigits: 2, + minimumFractionDigits: 2 + } + )} ${this.baseCurrency} (${netPerformanceInPercentageWithSign})` ]; } else { - const percentage = - (context.raw._data.allocationInPercentage as number) * 100; - - return [`${name ?? symbol}`, `${percentage.toFixed(2)}%`]; + return [ + `${name ?? symbol} (${allocationInPercentage})`, + '', + $localize`Performance`, + netPerformanceInPercentageWithSign + ]; } }, title: () => { From fe6dcdf6828014809f8ae3ccaf40ad7f1016d2f2 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Mon, 17 Feb 2025 23:52:02 +0530 Subject: [PATCH 16/71] feature/migrate to Angular control flow syntax (#4321) * Migrate to Angular control flow syntax * Update changelog --- CHANGELOG.md | 5 +++++ ...ghostfolio-premium-api-dialog.component.ts | 2 -- .../asset-profile-icon.component.ts | 2 -- .../rule-settings-dialog.component.ts | 9 +-------- .../alert-dialog/alert-dialog.component.ts | 3 +-- .../confirmation-dialog.component.ts | 3 +-- .../prompt-dialog/prompt-dialog.component.ts | 2 -- .../product-page.component.ts | 3 +-- .../benchmark-detail-dialog.component.ts | 2 -- .../data-provider-credits.component.html | 19 +++++++++++++------ .../data-provider-credits.component.ts | 2 -- ...cal-market-data-editor-dialog.component.ts | 2 -- .../tags-selector/tags-selector.component.ts | 2 -- .../trend-indicator.component.ts | 3 +-- 14 files changed, 23 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfd358244..96c90f4e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Migrated the `@ghostfolio/client` components to control flow +- Migrated the `@ghostfolio/ui` components to control flow + ### Fixed - Added missing assets in _Storybook_ setup diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts index 8c2907064..e42e6259e 100644 --- a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts @@ -3,7 +3,6 @@ import { DataService } from '@ghostfolio/client/services/data.service'; import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; -import { CommonModule } from '@angular/common'; import { Component, Inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { @@ -18,7 +17,6 @@ import { GhostfolioPremiumApiDialogParams } from './interfaces/interfaces'; @Component({ imports: [ - CommonModule, GfDialogFooterModule, GfDialogHeaderModule, GfPremiumIndicatorComponent, diff --git a/apps/client/src/app/components/asset-profile-icon/asset-profile-icon.component.ts b/apps/client/src/app/components/asset-profile-icon/asset-profile-icon.component.ts index 5db862969..179193da0 100644 --- a/apps/client/src/app/components/asset-profile-icon/asset-profile-icon.component.ts +++ b/apps/client/src/app/components/asset-profile-icon/asset-profile-icon.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, @@ -10,7 +9,6 @@ import { DataSource } from '@prisma/client'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - imports: [CommonModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-asset-profile-icon', styleUrls: ['./asset-profile-icon.component.scss'], diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts index 7ee9c66cf..b57bcb0fd 100644 --- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts +++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts @@ -1,6 +1,5 @@ import { XRayRulesSettings } from '@ghostfolio/common/interfaces'; -import { CommonModule } from '@angular/common'; import { Component, Inject } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -14,13 +13,7 @@ import { MatSliderModule } from '@angular/material/slider'; import { IRuleSettingsDialogParams } from './interfaces/interfaces'; @Component({ - imports: [ - CommonModule, - FormsModule, - MatButtonModule, - MatDialogModule, - MatSliderModule - ], + imports: [FormsModule, MatButtonModule, MatDialogModule, MatSliderModule], selector: 'gf-rule-settings-dialog', styleUrls: ['./rule-settings-dialog.scss'], templateUrl: './rule-settings-dialog.html' diff --git a/apps/client/src/app/core/notification/alert-dialog/alert-dialog.component.ts b/apps/client/src/app/core/notification/alert-dialog/alert-dialog.component.ts index 8aefe84cf..98b6043eb 100644 --- a/apps/client/src/app/core/notification/alert-dialog/alert-dialog.component.ts +++ b/apps/client/src/app/core/notification/alert-dialog/alert-dialog.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDialogModule, MatDialogRef } from '@angular/material/dialog'; @@ -6,7 +5,7 @@ import { MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { IAlertDialogParams } from './interfaces/interfaces'; @Component({ - imports: [CommonModule, MatButtonModule, MatDialogModule], + imports: [MatButtonModule, MatDialogModule], selector: 'gf-alert-dialog', styleUrls: ['./alert-dialog.scss'], templateUrl: './alert-dialog.html' diff --git a/apps/client/src/app/core/notification/confirmation-dialog/confirmation-dialog.component.ts b/apps/client/src/app/core/notification/confirmation-dialog/confirmation-dialog.component.ts index 9aced99cc..88e5113d7 100644 --- a/apps/client/src/app/core/notification/confirmation-dialog/confirmation-dialog.component.ts +++ b/apps/client/src/app/core/notification/confirmation-dialog/confirmation-dialog.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { Component, HostListener } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDialogModule, MatDialogRef } from '@angular/material/dialog'; @@ -7,7 +6,7 @@ import { ConfirmationDialogType } from './confirmation-dialog.type'; import { IConfirmDialogParams } from './interfaces/interfaces'; @Component({ - imports: [CommonModule, MatButtonModule, MatDialogModule], + imports: [MatButtonModule, MatDialogModule], selector: 'gf-confirmation-dialog', styleUrls: ['./confirmation-dialog.scss'], templateUrl: './confirmation-dialog.html' diff --git a/apps/client/src/app/core/notification/prompt-dialog/prompt-dialog.component.ts b/apps/client/src/app/core/notification/prompt-dialog/prompt-dialog.component.ts index 4ec634da9..6c8af4197 100644 --- a/apps/client/src/app/core/notification/prompt-dialog/prompt-dialog.component.ts +++ b/apps/client/src/app/core/notification/prompt-dialog/prompt-dialog.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -8,7 +7,6 @@ import { MatInputModule } from '@angular/material/input'; @Component({ imports: [ - CommonModule, FormsModule, MatButtonModule, MatDialogModule, diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts index 3a0ec4ffb..6a8543e71 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -3,14 +3,13 @@ import { Product } from '@ghostfolio/common/interfaces'; import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'; import { translate } from '@ghostfolio/ui/i18n'; -import { CommonModule } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { ActivatedRoute, RouterModule } from '@angular/router'; @Component({ host: { class: 'page' }, - imports: [CommonModule, MatButtonModule, RouterModule], + imports: [MatButtonModule, RouterModule], selector: 'gf-product-page', styleUrls: ['./product-page.scss'], templateUrl: './product-page.html' diff --git a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts index 38c6252a8..96dc6800e 100644 --- a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts +++ b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts @@ -8,7 +8,6 @@ import { } from '@ghostfolio/common/interfaces'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; -import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, @@ -33,7 +32,6 @@ import { BenchmarkDetailDialogParams } from './interfaces/interfaces'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'd-flex flex-column h-100' }, imports: [ - CommonModule, GfDialogFooterModule, GfDialogHeaderModule, GfLineChartComponent, diff --git a/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html b/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html index fb9f2c13b..921433620 100644 --- a/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html +++ b/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html @@ -1,9 +1,16 @@ - Market data provided by {{ + Market data provided by  + @for ( + dataProviderInfo of dataProviderInfos; + track dataProviderInfo; + let last = $last + ) { + {{ dataProviderInfo.name - }}, . + }} + @if (!last) { + ,  + } + } + . diff --git a/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.ts b/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.ts index 9be034e64..2d455c0d6 100644 --- a/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.ts +++ b/libs/ui/src/lib/data-provider-credits/data-provider-credits.component.ts @@ -1,6 +1,5 @@ import { DataProviderInfo } from '@ghostfolio/common/interfaces'; -import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, @@ -10,7 +9,6 @@ import { @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - imports: [CommonModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-data-provider-credits', styleUrls: ['./data-provider-credits.component.scss'], diff --git a/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts index 710cb4020..73f382c5e 100644 --- a/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts @@ -1,7 +1,6 @@ import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -29,7 +28,6 @@ import { HistoricalMarketDataEditorDialogParams } from './interfaces/interfaces' changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'h-100' }, imports: [ - CommonModule, FormsModule, MatButtonModule, MatDatepickerModule, diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.ts index 02b3a0a95..3c15e510c 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.ts @@ -1,5 +1,4 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -28,7 +27,6 @@ import { BehaviorSubject, Subject, takeUntil } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ - CommonModule, FormsModule, MatAutocompleteModule, MatChipsModule, diff --git a/libs/ui/src/lib/trend-indicator/trend-indicator.component.ts b/libs/ui/src/lib/trend-indicator/trend-indicator.component.ts index e44c41aa9..efb48c981 100644 --- a/libs/ui/src/lib/trend-indicator/trend-indicator.component.ts +++ b/libs/ui/src/lib/trend-indicator/trend-indicator.component.ts @@ -1,6 +1,5 @@ import { DateRange, MarketState } from '@ghostfolio/common/types'; -import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, @@ -11,7 +10,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - imports: [CommonModule, NgxSkeletonLoaderModule], + imports: [NgxSkeletonLoaderModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-trend-indicator', styleUrls: ['./trend-indicator.component.scss'], From 57957a7b30393e11fe924ade7f971fa6ae00cc2b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 17 Feb 2025 21:03:01 +0100 Subject: [PATCH 17/71] Bugfix/add missing CommonModule in tags selector component (#4335) * Add missing CommonModule (async pipe) --- libs/ui/src/lib/tags-selector/tags-selector.component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.ts index 3c15e510c..02b3a0a95 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.ts @@ -1,4 +1,5 @@ import { COMMA, ENTER } from '@angular/cdk/keycodes'; +import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -27,6 +28,7 @@ import { BehaviorSubject, Subject, takeUntil } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ + CommonModule, FormsModule, MatAutocompleteModule, MatChipsModule, From da79cf406f4b61e42b9be6cdc8df386bf8300dde Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 18 Feb 2025 16:56:50 +0100 Subject: [PATCH 18/71] Feature/reload available tags after creating custom tag in holding detail dialog (#4328) * Reload user to get available tags after creating custom tag * Update changelog --- CHANGELOG.md | 1 + .../holding-detail-dialog/holding-detail-dialog.component.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96c90f4e7..f5af20d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Reloaded the available tags after creating a custom tag in the holding detail dialog (experimental) - Migrated the `@ghostfolio/client` components to control flow - Migrated the `@ghostfolio/ui` components to control flow diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 69322b216..25317e0c5 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -175,6 +175,9 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { ] }); }), + switchMap(() => { + return this.userService.get(true); + }), takeUntil(this.unsubscribeSubject) ) .subscribe(); From b2698fccbd4ff1f90f9ae554da6c0dd15eaf6005 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 19 Feb 2025 17:25:54 +0100 Subject: [PATCH 19/71] Feature/improve validation of currency management in admin control panel (#4334) * Improve validation of currency management * Update changelog --- CHANGELOG.md | 1 + .../market-data/market-data.controller.ts | 5 ++-- .../create-asset-profile-dialog.component.ts | 29 ++++++++++++------- .../admin-overview.component.ts | 19 ------------ .../admin-overview/admin-overview.html | 10 ------- .../faq/self-hosting/self-hosting-page.html | 5 ++++ 6 files changed, 27 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5af20d2f..d6580eb33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Reloaded the available tags after creating a custom tag in the holding detail dialog (experimental) +- Improved the validation of the currency management in the admin control panel - Migrated the `@ghostfolio/client` components to control flow - Migrated the `@ghostfolio/ui` components to control flow 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 b4aef807a..933e70e9d 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 @@ -1,6 +1,7 @@ import { AdminService } from '@ghostfolio/api/app/admin/admin.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; +import { getCurrencyFromSymbol, isCurrency } from '@ghostfolio/common/helper'; import { MarketDataDetailsResponse } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { RequestWithUser } from '@ghostfolio/common/types'; @@ -42,7 +43,7 @@ export class MarketDataController { { dataSource, symbol } ]); - if (!assetProfile) { + if (!assetProfile && !isCurrency(getCurrencyFromSymbol(symbol))) { throw new HttpException( getReasonPhrase(StatusCodes.NOT_FOUND), StatusCodes.NOT_FOUND @@ -55,7 +56,7 @@ export class MarketDataController { ); const canReadOwnAssetProfile = - assetProfile.userId === this.request.user.id && + assetProfile?.userId === this.request.user.id && hasPermission( this.request.user.permissions, permissions.readMarketDataOfOwnAssetProfile 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 fa5e33f10..b0f69fa5c 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 @@ -15,9 +15,11 @@ import { FormControl, FormGroup, ValidationErrors, + ValidatorFn, Validators } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; +import { isISO4217CurrencyCode } from 'class-validator'; import { uniq } from 'lodash'; import { Subject, takeUntil } from 'rxjs'; @@ -52,9 +54,7 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy { this.createAssetProfileForm = this.formBuilder.group( { addCurrency: new FormControl(null, [ - Validators.maxLength(3), - Validators.minLength(3), - Validators.required + this.iso4217CurrencyCodeValidator() ]), addSymbol: new FormControl(null, [Validators.required]), searchSymbol: new FormControl(null, [Validators.required]) @@ -83,11 +83,11 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy { symbol: this.createAssetProfileForm.get('searchSymbol').value.symbol }); } else if (this.mode === 'currency') { - const currency = this.createAssetProfileForm - .get('addCurrency') - .value.toUpperCase(); + const currency = ( + this.createAssetProfileForm.get('addCurrency').value as string + ).toUpperCase(); - const currencies = uniq([...this.customCurrencies, currency]); + const currencies = uniq([...this.customCurrencies, currency]).sort(); this.dataService .putAdminSetting(PROPERTY_CURRENCIES, { @@ -109,10 +109,7 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy { const addCurrencyFormControl = this.createAssetProfileForm.get('addCurrency'); - if ( - addCurrencyFormControl.hasError('maxlength') || - addCurrencyFormControl.hasError('minlength') - ) { + if (addCurrencyFormControl.hasError('invalidCurrency')) { return true; } @@ -161,4 +158,14 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy { this.changeDetectorRef.markForCheck(); }); } + + private iso4217CurrencyCodeValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if (!isISO4217CurrencyCode(control.value?.toUpperCase())) { + return { invalidCurrency: true }; + } + + return null; + }; + } } 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 d217f871d..f54af4174 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 @@ -28,7 +28,6 @@ import { formatDistanceToNowStrict, parseISO } from 'date-fns'; -import { uniq } from 'lodash'; import { StringValue } from 'ms'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -122,24 +121,6 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { this.putAdminSetting({ key: PROPERTY_COUPONS, value: coupons }); } - public onAddCurrency() { - const currency = prompt($localize`Please add a currency:`); - - if (currency) { - if (currency.length === 3) { - const currencies = uniq([ - ...this.customCurrencies, - currency.toUpperCase() - ]); - this.putAdminSetting({ key: PROPERTY_CURRENCIES, value: currencies }); - } else { - this.notificationService.alert({ - title: $localize`${currency} is an invalid currency!` - }); - } - } - } - public onChangeCouponDuration(aCouponDuration: StringValue) { this.couponDuration = aCouponDuration; } 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 ba8545d16..a85c32d43 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -95,16 +95,6 @@ } -
- -
diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html index 7538678c3..3b2f6f605 100644 --- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html @@ -56,6 +56,11 @@
  • Click on the + button
  • Switch to Add Currency
  • Insert e.g. EUR for Euro
  • +
  • Select Filter by Currencies
  • +
  • Find the entry USDEUR
  • +
  • + Click the menu item Gather Historical Data in the dialog +
  • From 46878ea5a87a49299118dae41c99c0f0dca2e520 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 20 Feb 2025 17:46:10 +0100 Subject: [PATCH 20/71] Bugfix/improve error handling in http response interceptor (#4338) * Improve error handling * Update changelog --- CHANGELOG.md | 1 + apps/client/src/app/core/http-response.interceptor.ts | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6580eb33..b8020def5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Improved the error handling in the `HttpResponseInterceptor` - Added missing assets in _Storybook_ setup ## 2.139.1 - 2025-02-15 diff --git a/apps/client/src/app/core/http-response.interceptor.ts b/apps/client/src/app/core/http-response.interceptor.ts index 018e441fc..62c3540f7 100644 --- a/apps/client/src/app/core/http-response.interceptor.ts +++ b/apps/client/src/app/core/http-response.interceptor.ts @@ -108,10 +108,12 @@ export class HttpResponseInterceptor implements HttpInterceptor { }); } } else if (error.status === StatusCodes.UNAUTHORIZED) { - if (this.webAuthnService.isEnabled()) { - this.router.navigate(['/webauthn']); - } else if (!error.url.includes('/data-providers/ghostfolio/status')) { - this.tokenStorageService.signOut(); + if (!error.url.includes('/data-providers/ghostfolio/status')) { + if (this.webAuthnService.isEnabled()) { + this.router.navigate(['/webauthn']); + } else { + this.tokenStorageService.signOut(); + } } } From 69a0de28cd9afe11e6c0412fff979ee7dce1f84f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 20 Feb 2025 19:40:27 +0100 Subject: [PATCH 21/71] Bugfix/fix issue with symbol profile overrides in historical market data table of admin control panel (#4339) * Respect symbol profile overrides in market data controller (GET) * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.service.ts | 40 ++++++++++++++++--- .../symbol-profile/symbol-profile.service.ts | 11 +++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8020def5..ed9e778f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Improved the error handling in the `HttpResponseInterceptor` +- Fixed an issue while using symbol profile overrides in the historical market data table of the admin control panel - Added missing assets in _Storybook_ setup ## 2.139.1 - 2025-02-15 diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 142109725..ee79059f9 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -30,6 +30,7 @@ import { EnhancedSymbolProfile, Filter } from '@ghostfolio/common/interfaces'; +import { Sector } from '@ghostfolio/common/interfaces/sector.interface'; import { MarketDataPreset } from '@ghostfolio/common/types'; import { BadRequestException, Injectable, Logger } from '@nestjs/common'; @@ -259,7 +260,8 @@ export class AdminService { }, scraperConfiguration: true, sectors: true, - symbol: true + symbol: true, + SymbolProfileOverrides: true } }), this.prismaService.symbolProfile.count({ where }) @@ -313,11 +315,10 @@ export class AdminService { name, Order, sectors, - symbol + symbol, + SymbolProfileOverrides }) => { - const countriesCount = countries - ? Object.keys(countries).length - : 0; + let countriesCount = countries ? Object.keys(countries).length : 0; const lastMarketPrice = lastMarketPriceMap.get( getAssetProfileIdentifier({ dataSource, symbol }) @@ -331,7 +332,34 @@ export class AdminService { ); })?._count ?? 0; - const sectorsCount = sectors ? Object.keys(sectors).length : 0; + let sectorsCount = sectors ? Object.keys(sectors).length : 0; + + if (SymbolProfileOverrides) { + assetClass = SymbolProfileOverrides.assetClass ?? assetClass; + assetSubClass = + SymbolProfileOverrides.assetSubClass ?? assetSubClass; + + if ( + ( + SymbolProfileOverrides.countries as unknown as Prisma.JsonArray + )?.length > 0 + ) { + countriesCount = ( + SymbolProfileOverrides.countries as unknown as Prisma.JsonArray + ).length; + } + + name = SymbolProfileOverrides.name ?? name; + + if ( + (SymbolProfileOverrides.sectors as unknown as Sector[]) + ?.length > 0 + ) { + sectorsCount = ( + SymbolProfileOverrides.sectors as unknown as Prisma.JsonArray + ).length; + } + } return { assetClass, diff --git a/apps/api/src/services/symbol-profile/symbol-profile.service.ts b/apps/api/src/services/symbol-profile/symbol-profile.service.ts index df0526d9f..0dae63311 100644 --- a/apps/api/src/services/symbol-profile/symbol-profile.service.ts +++ b/apps/api/src/services/symbol-profile/symbol-profile.service.ts @@ -204,8 +204,7 @@ export class SymbolProfileService { ?.length > 0 ) { item.countries = this.getCountries( - item.SymbolProfileOverrides - ?.countries as unknown as Prisma.JsonArray + item.SymbolProfileOverrides.countries as unknown as Prisma.JsonArray ); } @@ -214,22 +213,22 @@ export class SymbolProfileService { ?.length > 0 ) { item.holdings = this.getHoldings( - item.SymbolProfileOverrides?.holdings as unknown as Prisma.JsonArray + item.SymbolProfileOverrides.holdings as unknown as Prisma.JsonArray ); } - item.name = item.SymbolProfileOverrides?.name ?? item.name; + item.name = item.SymbolProfileOverrides.name ?? item.name; if ( (item.SymbolProfileOverrides.sectors as unknown as Sector[])?.length > 0 ) { item.sectors = this.getSectors( - item.SymbolProfileOverrides?.sectors as unknown as Prisma.JsonArray + item.SymbolProfileOverrides.sectors as unknown as Prisma.JsonArray ); } - item.url = item.SymbolProfileOverrides?.url ?? item.url; + item.url = item.SymbolProfileOverrides.url ?? item.url; delete item.SymbolProfileOverrides; } From f1acff1c7656d9b3383d94e32a5e41af2503687f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Feb 2025 20:51:17 +0100 Subject: [PATCH 22/71] Feature/update locales (#4333) * Update translations * Update changelog --------- Co-authored-by: github-actions[bot] Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 1 + apps/client/src/locales/messages.ca.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.de.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.es.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.fr.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.it.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.nl.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.pl.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.pt.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.tr.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.uk.xlf | 114 ++++++++++++------------ apps/client/src/locales/messages.xlf | 110 +++++++++++------------ apps/client/src/locales/messages.zh.xlf | 114 ++++++++++++------------ 13 files changed, 683 insertions(+), 682 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed9e778f6..b0a5b23e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the validation of the currency management in the admin control panel - Migrated the `@ghostfolio/client` components to control flow - Migrated the `@ghostfolio/ui` components to control flow +- Improved the language localization for German (`de`) ### Fixed diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index d70c773e6..a36fb152f 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -447,7 +447,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -583,7 +583,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -803,7 +803,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -1219,7 +1219,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1958,28 +1958,12 @@ 124 - - Please add a currency: - Si us plau, afegiu una divisa: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - - - is an invalid currency! - no és una divisa vàlida! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - Do you really want to delete this coupon? Està segur qeu vol eliminar aquest cupó? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -1987,7 +1971,7 @@ Està segur que vol eliminar aquesta divisa? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -1995,7 +1979,7 @@ Està segur que vol eliminar aquest missatge del sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -2003,7 +1987,7 @@ Està segur que vol depurar el cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -2011,7 +1995,7 @@ Si us plau, afegeixi el seu missatge del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -2061,17 +2045,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - User Signup Registrar Usuari apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -2079,7 +2059,7 @@ Mode Només Lecutra apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -2087,7 +2067,7 @@ Recollida de Dades apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -2095,7 +2075,7 @@ Missatge del Sistema apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -2103,7 +2083,7 @@ Estableix el Missatge apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -2111,7 +2091,7 @@ Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -2119,7 +2099,7 @@ Afegir apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -2131,7 +2111,7 @@ Ordre apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -2139,7 +2119,7 @@ Depurar el Cache apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2355,7 +2335,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -5095,7 +5075,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -5611,7 +5591,7 @@ Switzerland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5623,7 +5603,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6775,7 +6755,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index b7ff00641..3983ca586 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -298,7 +298,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -617,20 +617,12 @@ 44 - - Please add a currency: - Bitte Währung hinzufügen: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Möchtest du diesen Gutscheincode wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -638,7 +630,7 @@ Möchtest du diese Währung wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -646,7 +638,7 @@ Möchtest du den Cache wirklich leeren? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -654,7 +646,7 @@ Bitte gebe deine Systemmeldung ein: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -716,17 +708,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - System Message Systemmeldung apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -734,7 +722,7 @@ Systemmeldung setzen apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -742,7 +730,7 @@ Lese-Modus apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -750,7 +738,7 @@ Gutscheincodes apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -758,7 +746,7 @@ Hinzufügen apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -770,7 +758,7 @@ Verwaltung apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -778,7 +766,7 @@ Cache leeren apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2410,7 +2398,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -3346,7 +3334,7 @@ Benutzer Registrierung apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -5316,7 +5304,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -5405,7 +5393,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -5659,7 +5647,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -5767,7 +5755,7 @@ Schweiz apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5779,7 +5767,7 @@ Weltweit apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6155,7 +6143,7 @@ Möchtest du diese Systemmeldung wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6214,14 +6202,6 @@ 109 - - is an invalid currency! - ist eine ungültige Währung! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. Wenn eine Übersetzung fehlt, unterstütze uns bitte dabei, sie hier zu ergänzen. @@ -6327,7 +6307,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6483,7 +6463,7 @@ Daten einholen apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6775,7 +6755,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budgetierung apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Persönliche Finanzen apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Datenschutz apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Vermögen apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Vermögensverwaltung apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Bitte gebe deinen Ghostfolio API-Schlüssel ein. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Änderung + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index e12415868..e41708851 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -299,7 +299,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -618,20 +618,12 @@ 44 - - Please add a currency: - Por favor, añade una divisa: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? ¿Estás seguro de eliminar este cupón? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -639,7 +631,7 @@ ¿Estás seguro de eliminar esta divisa? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -647,7 +639,7 @@ ¿Estás seguro de limpiar la caché? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -655,7 +647,7 @@ Por favor, establece tu mensaje del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -717,17 +709,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - System Message Mensaje del sistema apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -735,7 +723,7 @@ Establecer mensaje apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -743,7 +731,7 @@ Modo de solo lectura apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -751,7 +739,7 @@ Cupones apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -759,7 +747,7 @@ Añadir apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -771,7 +759,7 @@ Tareas domésticas apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -779,7 +767,7 @@ Limpiar caché apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2411,7 +2399,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -3347,7 +3335,7 @@ Registro de usuario apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -5317,7 +5305,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -5406,7 +5394,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -5660,7 +5648,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -5768,7 +5756,7 @@ Switzerland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5780,7 +5768,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6156,7 +6144,7 @@ Do you really want to delete this system message? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6215,14 +6203,6 @@ 109 - - is an invalid currency! - is an invalid currency! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. If a translation is missing, kindly support us in extending it here. @@ -6328,7 +6308,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6484,7 +6464,7 @@ Data Gathering apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6776,7 +6756,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6784,7 +6764,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6792,7 +6772,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6800,7 +6780,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6808,7 +6788,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6816,7 +6796,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6824,7 +6804,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6832,7 +6812,7 @@ Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6840,7 +6820,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6848,7 +6828,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6856,7 +6836,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6864,7 +6844,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6872,7 +6852,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6880,7 +6860,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7634,7 +7614,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7765,6 +7745,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index bc5d94438..aa0dd2891 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -358,7 +358,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -877,20 +877,12 @@ 339 - - Please add a currency: - Veuillez ajouter une devise : - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Voulez-vous vraiment supprimer ce code promotionnel ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -898,7 +890,7 @@ Voulez-vous vraiment supprimer cette devise ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -906,7 +898,7 @@ Voulez-vous vraiment vider le cache ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -914,7 +906,7 @@ Veuillez définir votre message système : apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -956,10 +948,6 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - Tags @@ -982,7 +970,7 @@ Inscription de Nouveaux Utilisateurs apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -990,7 +978,7 @@ Mode Lecture Seule apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -998,7 +986,7 @@ Message Système apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -1006,7 +994,7 @@ Définir Message apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -1014,7 +1002,7 @@ Codes promotionnels apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -1022,7 +1010,7 @@ Ajouter apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -1034,7 +1022,7 @@ Maintenance apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -1042,7 +1030,7 @@ Vider le Cache apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -1150,7 +1138,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -5316,7 +5304,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -5405,7 +5393,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -5659,7 +5647,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -5767,7 +5755,7 @@ Suisse apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5779,7 +5767,7 @@ Mondial apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6155,7 +6143,7 @@ Confirmer la suppresion de ce message système? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6214,14 +6202,6 @@ 109 - - is an invalid currency! - est une devise non valide ! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. Si une traduction est manquante, veuillez nous aider à compléter la traduction here. @@ -6327,7 +6307,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6483,7 +6463,7 @@ Collecter les données apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6775,7 +6755,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budget apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Communauté apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Investisseur apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Confidentialité apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Logiciels apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Outils apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ Expérience Utilisateur apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index f6761f2c7..a17749690 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -299,7 +299,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -618,20 +618,12 @@ 44 - - Please add a currency: - Aggiungi una valuta: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Vuoi davvero eliminare questo buono? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -639,7 +631,7 @@ Vuoi davvero eliminare questa valuta? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -647,7 +639,7 @@ Vuoi davvero svuotare la cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -655,7 +647,7 @@ Imposta il messaggio di sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -717,17 +709,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - System Message Messaggio di sistema apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -735,7 +723,7 @@ Imposta messaggio apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -743,7 +731,7 @@ Modalità di sola lettura apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -751,7 +739,7 @@ Buoni sconto apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -759,7 +747,7 @@ Aggiungi apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -771,7 +759,7 @@ Bilancio domestico apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -779,7 +767,7 @@ Svuota la cache apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2411,7 +2399,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -3347,7 +3335,7 @@ Registrazione utente apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -5317,7 +5305,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -5406,7 +5394,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -5660,7 +5648,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -5768,7 +5756,7 @@ Svizzera apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5780,7 +5768,7 @@ Globale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6156,7 +6144,7 @@ Confermi di voler cancellare questo messaggio di sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6215,14 +6203,6 @@ 109 - - is an invalid currency! - non è una valuta valida! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. Se manca una traduzione, puoi aiutarci modificando questo file: here. @@ -6328,7 +6308,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6484,7 +6464,7 @@ Raccolta Dati apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6776,7 +6756,7 @@ Alternativa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6784,7 +6764,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6792,7 +6772,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6800,7 +6780,7 @@ Comunità apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6808,7 +6788,7 @@ Ufficio familiare apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6816,7 +6796,7 @@ Investitore apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6824,7 +6804,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6832,7 +6812,7 @@ Finanza Personale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6840,7 +6820,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6848,7 +6828,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6856,7 +6836,7 @@ Strumento apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6864,7 +6844,7 @@ Esperienza Utente apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6872,7 +6852,7 @@ Ricchezza apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6880,7 +6860,7 @@ Gestione Patrimoniale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7634,7 +7614,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7765,6 +7745,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index aab3a3939..d8609b1b5 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -298,7 +298,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -617,20 +617,12 @@ 44 - - Please add a currency: - Voeg een valuta toe: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Wil je deze coupon echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -638,7 +630,7 @@ Wil je deze valuta echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -646,7 +638,7 @@ Wil je echt de cache legen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -654,7 +646,7 @@ Stel je systeemboodschap in: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -716,17 +708,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - System Message Systeembericht apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -734,7 +722,7 @@ Bericht instellen apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -742,7 +730,7 @@ Alleen lezen apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -750,7 +738,7 @@ Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -758,7 +746,7 @@ Toevoegen apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -770,7 +758,7 @@ Huishouding apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -778,7 +766,7 @@ Cache legen apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2410,7 +2398,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -3346,7 +3334,7 @@ Account aanmaken apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -5316,7 +5304,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -5405,7 +5393,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -5659,7 +5647,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -5767,7 +5755,7 @@ Zwitserland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5779,7 +5767,7 @@ Wereldwijd apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6155,7 +6143,7 @@ Do you really want to delete this system message? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6214,14 +6202,6 @@ 109 - - is an invalid currency! - is an invalid currency! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. If a translation is missing, kindly support us in extending it here. @@ -6327,7 +6307,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6483,7 +6463,7 @@ Data Gathering apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6775,7 +6755,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index e2e157e14..c53b6177f 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -87,7 +87,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -189,7 +189,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -443,7 +443,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -1147,7 +1147,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1782,20 +1782,12 @@ 124 - - Please add a currency: - Proszę dodać walutę: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Czy naprawdę chcesz usunąć ten kupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -1803,7 +1795,7 @@ Czy naprawdę chcesz usunąć tę walutę? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -1811,7 +1803,7 @@ Czy naprawdę chcesz usunąć tę wiadomość systemową? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -1819,7 +1811,7 @@ Czy naprawdę chcesz wyczyścić pamięć podręczną? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -1827,7 +1819,7 @@ Proszę ustawić swoją wiadomość systemową: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -1877,17 +1869,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - User Signup Rejestracja Użytkownika apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -1895,7 +1883,7 @@ Tryb Tylko do Odczytu apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -1903,7 +1891,7 @@ Wiadomość Systemowa apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -1911,7 +1899,7 @@ Ustaw Wiadomość apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -1919,7 +1907,7 @@ Kupony apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -1927,7 +1915,7 @@ Dodaj apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -1939,7 +1927,7 @@ Konserwacja apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -1947,7 +1935,7 @@ Wyczyszczenie pamięci podręcznej apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2183,7 +2171,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -5391,7 +5379,7 @@ Szwajcaria apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5403,7 +5391,7 @@ Globalny apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6214,14 +6202,6 @@ 109 - - is an invalid currency! - to nieprawidłowa waluta! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. Jeżeli brakuje jakiegoś tłumaczenia, uprzejmie prosimy o wsparcie w jego uzupełnieniu tutaj. @@ -6327,7 +6307,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6483,7 +6463,7 @@ Gromadzenie Danych apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6775,7 +6755,7 @@ Alternatywa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ Aplikacja apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budżetowanie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Społeczność apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Biuro Rodzinne apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Inwestor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Otwarty Kod Źródłowy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Finanse Osobiste apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Prywatność apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Oprogramowanie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Narzędzie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ Doświadczenie Użytkownika apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Majątek apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Zarządzanie Majątkiem apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 69af89c1b..e2a79168a 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -358,7 +358,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -781,20 +781,12 @@ 45 - - Please add a currency: - Por favor, adicione uma moeda: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Deseja realmente eliminar este cupão? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -802,7 +794,7 @@ Deseja realmente excluir esta moeda? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -810,7 +802,7 @@ Deseja realmente limpar a cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -818,7 +810,7 @@ Por favor, defina a sua mensagem do sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -852,17 +844,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - System Message Mensagem de Sistema apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -870,7 +858,7 @@ Definir Mensagem apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -878,7 +866,7 @@ Modo Somente Leitura apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -886,7 +874,7 @@ Cupões apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -894,7 +882,7 @@ Adicionar apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -906,7 +894,7 @@ Manutenção apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -914,7 +902,7 @@ Limpar Cache apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -1022,7 +1010,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -3278,7 +3266,7 @@ Registo do Utilizador apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -5316,7 +5304,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -5405,7 +5393,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -5659,7 +5647,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -5767,7 +5755,7 @@ Switzerland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5779,7 +5767,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6155,7 +6143,7 @@ Do you really want to delete this system message? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6214,14 +6202,6 @@ 109 - - is an invalid currency! - is an invalid currency! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. If a translation is missing, kindly support us in extending it here. @@ -6327,7 +6307,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6483,7 +6463,7 @@ Data Gathering apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6775,7 +6755,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index c1e9963f7..35415106f 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -87,7 +87,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -189,7 +189,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -443,7 +443,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -1111,7 +1111,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1690,20 +1690,12 @@ 124 - - Please add a currency: - Lütfen bir para birimi giriniz: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - Do you really want to delete this coupon? Önbelleği temizlemeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -1711,7 +1703,7 @@ Bu para birimini silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -1719,7 +1711,7 @@ Önbelleği temizlemeyi gerçekten istiyor musunuz apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -1727,7 +1719,7 @@ Lütfen sistem mesajınızı belirleyin: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -1769,10 +1761,6 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - Tags @@ -1795,7 +1783,7 @@ Kullanıcı Kaydı apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -1803,7 +1791,7 @@ Salt okunur mod apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -1811,7 +1799,7 @@ Sistem Mesajı apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -1819,7 +1807,7 @@ Mesaj Belirle apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -1827,7 +1815,7 @@ Kupon apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -1835,7 +1823,7 @@ Ekle apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -1847,7 +1835,7 @@ Genel Ayarlar apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -1855,7 +1843,7 @@ Önbelleği temizle apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2047,7 +2035,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -4867,7 +4855,7 @@ İsviçre apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -4879,7 +4867,7 @@ Küresel apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6155,7 +6143,7 @@ Bu sistem mesajını silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -6214,14 +6202,6 @@ 109 - - is an invalid currency! - is an invalid currency! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - If a translation is missing, kindly support us in extending it here. If a translation is missing, kindly support us in extending it here. @@ -6327,7 +6307,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6483,7 +6463,7 @@ Data Gathering apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6775,7 +6755,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6783,7 +6763,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6791,7 +6771,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6799,7 +6779,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6807,7 +6787,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6815,7 +6795,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6823,7 +6803,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6831,7 +6811,7 @@ Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6839,7 +6819,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6847,7 +6827,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6855,7 +6835,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6863,7 +6843,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6871,7 +6851,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6879,7 +6859,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7633,7 +7613,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index f582408b7..e013a621a 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -447,7 +447,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -583,7 +583,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -803,7 +803,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -1235,7 +1235,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1933,10 +1933,6 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - Name, symbol or ISIN @@ -1958,28 +1954,12 @@ 49 - - Please add a currency: - Будь ласка, додайте валюту: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - - - is an invalid currency! - є недопустимою валютою! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - Do you really want to delete this coupon? Ви дійсно хочете видалити цей купон? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -1987,7 +1967,7 @@ Ви дійсно хочете видалити цю валюту? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -1995,7 +1975,7 @@ Ви дійсно хочете видалити це системне повідомлення? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -2003,7 +1983,7 @@ Ви дійсно хочете очистити кеш? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -2011,7 +1991,7 @@ Будь ласка, встановіть ваше системне повідомлення: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -2059,7 +2039,7 @@ Реєстрація користувача apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -2067,7 +2047,7 @@ Режим лише для читання apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -2075,7 +2055,7 @@ Збір даних apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -2083,7 +2063,7 @@ Системне повідомлення apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -2091,7 +2071,7 @@ Встановити повідомлення apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -2099,7 +2079,7 @@ Купони apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -2107,7 +2087,7 @@ Додати apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -2119,7 +2099,7 @@ Прибирання apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -2127,7 +2107,7 @@ Очистити кеш apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2279,7 +2259,7 @@ Будь ласка, введіть ваш ключ API Ghostfolio. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -2487,7 +2467,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -5371,7 +5351,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6025,7 +6005,7 @@ Швейцарія apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -6037,7 +6017,7 @@ Глобальний apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6049,7 +6029,7 @@ Альтернатива apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6057,7 +6037,7 @@ Додаток apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6065,7 +6045,7 @@ Бюджетування apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6073,7 +6053,7 @@ Спільнота apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6081,7 +6061,7 @@ Сімейний офіс apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6089,7 +6069,7 @@ Інвестор apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6097,7 +6077,7 @@ Відкритий код apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6105,7 +6085,7 @@ Особисті фінанси apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6113,7 +6093,7 @@ Конфіденційність apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6121,7 +6101,7 @@ Програмне забезпечення apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6129,7 +6109,7 @@ Інструмент apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6137,7 +6117,7 @@ Користувацький досвід apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6145,7 +6125,7 @@ Багатство apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6153,7 +6133,7 @@ Управління багатством apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7764,6 +7744,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index eba1176e5..7d93b392f 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -87,7 +87,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -187,7 +187,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -435,7 +435,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -1114,7 +1114,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1700,53 +1700,39 @@ 124 - - Please add a currency: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - - - is an invalid currency! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - Do you really want to delete this coupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 Do you really want to delete this currency? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 Do you really want to delete this system message? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 Do you really want to flush the cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 Please set your system message: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -1790,51 +1776,47 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - User Signup apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 Read-only Mode apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 System Message apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 Set Message apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 Add apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -1845,14 +1827,14 @@ Housekeeping apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 Flush Cache apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2065,7 +2047,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -4965,7 +4947,7 @@ Switzerland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -4976,7 +4958,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -5780,7 +5762,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -5925,7 +5907,7 @@ Data Gathering apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6153,14 +6135,14 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6202,35 +6184,35 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -6258,28 +6240,28 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6307,7 +6289,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6321,7 +6303,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6356,7 +6338,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6906,7 +6888,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7021,6 +7003,24 @@ 374 + + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 16e86c2f2..10fc585a8 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -88,7 +88,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 23 + 22 @@ -190,7 +190,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 24 + 23 @@ -444,7 +444,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 26 + 25 @@ -1156,7 +1156,7 @@ apps/client/src/app/components/admin-overview/admin-overview.html - 206 + 196 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1791,28 +1791,12 @@ 124 - - Please add a currency: - 请添加货币: - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 126 - - - - is an invalid currency! - 是无效的货币! - - apps/client/src/app/components/admin-overview/admin-overview.component.ts - 137 - - Do you really want to delete this coupon? 您确实要删除此优惠券吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 156 + 137 @@ -1820,7 +1804,7 @@ 您真的要删除该货币吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 169 + 150 @@ -1828,7 +1812,7 @@ 您真的要删除这条系统消息吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 182 + 163 @@ -1836,7 +1820,7 @@ 您真的要刷新缓存吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 187 @@ -1844,7 +1828,7 @@ 请设置您的系统消息: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 226 + 207 @@ -1894,17 +1878,13 @@ apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 22 - - apps/client/src/app/components/admin-overview/admin-overview.html - 105 - User Signup 用户注册 apps/client/src/app/components/admin-overview/admin-overview.html - 111 + 101 @@ -1912,7 +1892,7 @@ 只读模式 apps/client/src/app/components/admin-overview/admin-overview.html - 125 + 115 @@ -1920,7 +1900,7 @@ 系统信息 apps/client/src/app/components/admin-overview/admin-overview.html - 149 + 139 @@ -1928,7 +1908,7 @@ 设置留言 apps/client/src/app/components/admin-overview/admin-overview.html - 171 + 161 @@ -1936,7 +1916,7 @@ 优惠券 apps/client/src/app/components/admin-overview/admin-overview.html - 179 + 169 @@ -1944,7 +1924,7 @@ 添加 apps/client/src/app/components/admin-overview/admin-overview.html - 239 + 229 libs/ui/src/lib/account-balances/account-balances.component.html @@ -1956,7 +1936,7 @@ 家政 apps/client/src/app/components/admin-overview/admin-overview.html - 247 + 237 @@ -1964,7 +1944,7 @@ 刷新缓存 apps/client/src/app/components/admin-overview/admin-overview.html - 251 + 241 @@ -2200,7 +2180,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 93 @@ -5432,7 +5412,7 @@ 瑞士 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 59 + 58 libs/ui/src/lib/i18n.ts @@ -5444,7 +5424,7 @@ 全球的 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 60 + 59 libs/ui/src/lib/i18n.ts @@ -6352,7 +6332,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 87 @@ -6516,7 +6496,7 @@ 数据收集 apps/client/src/app/components/admin-overview/admin-overview.html - 137 + 127 @@ -6776,7 +6756,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 81 @@ -6784,7 +6764,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 82 @@ -6792,7 +6772,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 83 @@ -6800,7 +6780,7 @@ Community apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 84 @@ -6808,7 +6788,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 85 @@ -6816,7 +6796,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 88 @@ -6824,7 +6804,7 @@ Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 89 @@ -6832,7 +6812,7 @@ Personal Finance apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 91 @@ -6840,7 +6820,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 92 @@ -6848,7 +6828,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 94 @@ -6856,7 +6836,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 95 @@ -6864,7 +6844,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 96 @@ -6872,7 +6852,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 97 @@ -6880,7 +6860,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 98 @@ -7634,7 +7614,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts - 59 + 57 @@ -7765,6 +7745,26 @@ 374 + + Change + Change + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + + Performance + Performance + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 365 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 378 + + From c90dca565fc7e3ee933582eed3091265a26133db Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 20 Feb 2025 20:53:38 +0100 Subject: [PATCH 23/71] Release 2.140.0 (#4345) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0a5b23e8..d3df5a97c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.140.0 - 2025-02-20 ### Changed diff --git a/package-lock.json b/package-lock.json index 21cc622d5..e604c275b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.139.1", + "version": "2.140.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.139.1", + "version": "2.140.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index a97178081..c3bd3a0d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.139.1", + "version": "2.140.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From fc3613be4e50936212576b91364b6517992c6b70 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:42:34 +0100 Subject: [PATCH 24/71] Feature/upgrade prettier to version 3.5.1 (#4342) * Upgrade prettier to version 3.5.1 * Update changelog --- CHANGELOG.md | 6 ++++++ package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3df5a97c..3bb4e27be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Upgraded `prettier` from version `3.4.2` to `3.5.1` + ## 2.140.0 - 2025-02-20 ### Changed diff --git a/package-lock.json b/package-lock.json index e604c275b..0fd7572e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -149,7 +149,7 @@ "jest-environment-jsdom": "29.7.0", "jest-preset-angular": "14.4.2", "nx": "20.3.2", - "prettier": "3.4.2", + "prettier": "3.5.1", "prettier-plugin-organize-attributes": "1.0.0", "prisma": "6.3.0", "react": "18.2.0", @@ -27104,9 +27104,9 @@ } }, "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", + "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index c3bd3a0d0..2a3881183 100644 --- a/package.json +++ b/package.json @@ -195,7 +195,7 @@ "jest-environment-jsdom": "29.7.0", "jest-preset-angular": "14.4.2", "nx": "20.3.2", - "prettier": "3.4.2", + "prettier": "3.5.1", "prettier-plugin-organize-attributes": "1.0.0", "prisma": "6.3.0", "react": "18.2.0", From 05b0728b2ac7838ba7b2c614335f379466120dcb Mon Sep 17 00:00:00 2001 From: Sayed Murtadha Ahmed Date: Sat, 22 Feb 2025 11:20:39 +0300 Subject: [PATCH 25/71] Feature/extend export by tags (#4337) * Extend export by tags * Update changelog --- CHANGELOG.md | 4 +++ apps/api/src/app/export/export.module.ts | 3 +- apps/api/src/app/export/export.service.ts | 30 ++++++++++++++----- .../src/lib/interfaces/export.interface.ts | 11 +++---- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bb4e27be..eac524907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Extended the export functionality by the tags + ### Changed - Upgraded `prettier` from version `3.4.2` to `3.5.1` diff --git a/apps/api/src/app/export/export.module.ts b/apps/api/src/app/export/export.module.ts index 048c60359..892a761cc 100644 --- a/apps/api/src/app/export/export.module.ts +++ b/apps/api/src/app/export/export.module.ts @@ -1,6 +1,7 @@ import { AccountModule } from '@ghostfolio/api/app/account/account.module'; import { OrderModule } from '@ghostfolio/api/app/order/order.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; +import { TagModule } from '@ghostfolio/api/services/tag/tag.module'; import { Module } from '@nestjs/common'; @@ -8,7 +9,7 @@ import { ExportController } from './export.controller'; import { ExportService } from './export.service'; @Module({ - imports: [AccountModule, ApiModule, OrderModule], + imports: [AccountModule, ApiModule, OrderModule, TagModule], controllers: [ExportController], providers: [ExportService] }) diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 1ff18ce9c..219ffffda 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -1,6 +1,7 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { OrderService } from '@ghostfolio/api/app/order/order.service'; import { environment } from '@ghostfolio/api/environments/environment'; +import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { Filter, Export } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; @@ -9,7 +10,8 @@ import { Injectable } from '@nestjs/common'; export class ExportService { public constructor( private readonly accountService: AccountService, - private readonly orderService: OrderService + private readonly orderService: OrderService, + private readonly tagService: TagService ) {} public async export({ @@ -60,9 +62,21 @@ export class ExportService { }); } + const tags = (await this.tagService.getTagsForUser(userId)) + .filter(({ isUsed }) => { + return isUsed; + }) + .map(({ id, name }) => { + return { + id, + name + }; + }); + return { meta: { date: new Date().toISOString(), version: environment.version }, accounts, + tags, activities: activities.map( ({ accountId, @@ -72,6 +86,7 @@ export class ExportService { id, quantity, SymbolProfile, + tags: currentTags, type, unitPrice }) => { @@ -86,13 +101,12 @@ export class ExportService { currency: SymbolProfile.currency, dataSource: SymbolProfile.dataSource, date: date.toISOString(), - symbol: - type === 'FEE' || - type === 'INTEREST' || - type === 'ITEM' || - type === 'LIABILITY' - ? SymbolProfile.name - : SymbolProfile.symbol + symbol: ['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(type) + ? SymbolProfile.name + : SymbolProfile.symbol, + tags: currentTags.map(({ id: tagId }) => { + return tagId; + }) }; } ), diff --git a/libs/common/src/lib/interfaces/export.interface.ts b/libs/common/src/lib/interfaces/export.interface.ts index de3d7cf02..1257e50bc 100644 --- a/libs/common/src/lib/interfaces/export.interface.ts +++ b/libs/common/src/lib/interfaces/export.interface.ts @@ -1,10 +1,6 @@ -import { Account, Order } from '@prisma/client'; +import { Account, Order, Tag } from '@prisma/client'; export interface Export { - meta: { - date: string; - version: string; - }; accounts: Omit[]; activities: (Omit< Order, @@ -16,5 +12,10 @@ export interface Export { | 'updatedAt' | 'userId' > & { date: string; symbol: string })[]; + meta: { + date: string; + version: string; + }; + tags: Omit[]; user: { settings: { currency: string } }; } From 7577a452f0b5f042c5dbd0c31e9a79ebe5867ea9 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Sun, 23 Feb 2025 13:20:59 +0530 Subject: [PATCH 26/71] Feature/add activities count to GET user endpoint (#4351) * Add activities count to GET user endpoint * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/user/user.service.ts | 9 +++++++-- libs/common/src/lib/interfaces/user.interface.ts | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eac524907..7fd3aaf6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Extended the export functionality by the tags +- Extended the user endpoint `GET api/v1/user` by the activities count ### Changed diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index dcf9d9404..40bc1b2b5 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -86,6 +86,9 @@ export class UserService { orderBy: { alias: 'asc' }, where: { GranteeUser: { id } } }), + this.prismaService.order.count({ + where: { userId: id } + }), this.prismaService.order.findFirst({ orderBy: { date: 'asc' @@ -96,8 +99,9 @@ export class UserService { ]); const access = userData[0]; - const firstActivity = userData[1]; - let tags = userData[2]; + const activitiesCount = userData[1]; + const firstActivity = userData[2]; + let tags = userData[3]; let systemMessage: SystemMessage; @@ -117,6 +121,7 @@ export class UserService { } return { + activitiesCount, id, permissions, subscription, diff --git a/libs/common/src/lib/interfaces/user.interface.ts b/libs/common/src/lib/interfaces/user.interface.ts index 667e59fd8..84f48d1dc 100644 --- a/libs/common/src/lib/interfaces/user.interface.ts +++ b/libs/common/src/lib/interfaces/user.interface.ts @@ -10,6 +10,7 @@ import { UserSettings } from './user-settings.interface'; export interface User { access: Pick[]; accounts: Account[]; + activitiesCount: number; dateOfFirstActivity: Date; id: string; permissions: string[]; From 190abdf9cc390eefeeee7028cf2eba0c30256303 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 24 Feb 2025 13:53:05 +0100 Subject: [PATCH 27/71] Bugfix/improve numeric comparison of strings in value component (#4330) * Improve numeric comparison of strings * Update changelog --- CHANGELOG.md | 4 ++++ libs/ui/src/lib/value/value.component.html | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fd3aaf6b..019bf4b6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgraded `prettier` from version `3.4.2` to `3.5.1` +### Fixed + +- Improved the numeric comparison of strings in the value component + ## 2.140.0 - 2025-02-20 ### Changed diff --git a/libs/ui/src/lib/value/value.component.html b/libs/ui/src/lib/value/value.component.html index a691c54e8..0ead7497e 100644 --- a/libs/ui/src/lib/value/value.component.html +++ b/libs/ui/src/lib/value/value.component.html @@ -10,8 +10,8 @@ > -
    +
    -
    -
    +
    +
    +
    -
    Date: Mon, 24 Feb 2025 21:54:53 +0100 Subject: [PATCH 28/71] Feature/extend portfolio snapshot by activities count (#4352) * Extend portfolio snapshot by activities count * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/portfolio/calculator/portfolio-calculator.ts | 1 + .../src/app/portfolio/calculator/twr/portfolio-calculator.ts | 3 +++ libs/common/src/lib/models/portfolio-snapshot.ts | 2 ++ 4 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 019bf4b6a..ecbcdc820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Extended the export functionality by the tags +- Extended the portfolio snapshot in the portfolio calculator by the activities count - Extended the user endpoint `GET api/v1/user` by the activities count ### Changed diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 2f8a9f0c9..e9c4fdcce 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -175,6 +175,7 @@ export abstract class PortfolioCalculator { if (!transactionPoints.length) { return { + activitiesCount: 0, currentValueInBaseCurrency: new Big(0), errors: [], hasErrors: false, diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts index cf808debb..209a0efd5 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts @@ -101,6 +101,9 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { totalInterestWithCurrencyEffect, totalInvestment, totalInvestmentWithCurrencyEffect, + activitiesCount: this.activities.filter(({ type }) => { + return ['BUY', 'SELL'].includes(type); + }).length, errors: [], historicalData: [], totalLiabilitiesWithCurrencyEffect: new Big(0), diff --git a/libs/common/src/lib/models/portfolio-snapshot.ts b/libs/common/src/lib/models/portfolio-snapshot.ts index 46bd5c18f..d0c4c66e0 100644 --- a/libs/common/src/lib/models/portfolio-snapshot.ts +++ b/libs/common/src/lib/models/portfolio-snapshot.ts @@ -9,6 +9,8 @@ import { Big } from 'big.js'; import { Transform, Type } from 'class-transformer'; export class PortfolioSnapshot { + activitiesCount: number; + @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) currentValueInBaseCurrency: Big; From 8f165d46e03e81d70abc62c625542823b6d60db1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 25 Feb 2025 19:48:22 +0100 Subject: [PATCH 29/71] Feature/add cusip to asset profile model (#4347) * Add CUSIP * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/import/import.service.ts | 2 ++ .../migration.sql | 5 +++++ prisma/migrations/migration_lock.toml | 2 +- prisma/schema.prisma | 2 ++ 5 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20250222084717_added_cusip_to_symbol_profile/migration.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index ecbcdc820..b4d6f0a74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Extended the export functionality by the tags - Extended the portfolio snapshot in the portfolio calculator by the activities count - Extended the user endpoint `GET api/v1/user` by the activities count +- Added `cusip` to the asset profile model ### Changed diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index eb1b841c4..698d13e2b 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -293,6 +293,7 @@ export class ImportService { assetSubClass, countries, createdAt, + cusip, dataSource, figi, figiComposite, @@ -367,6 +368,7 @@ export class ImportService { assetSubClass, countries, createdAt, + cusip, dataSource, figi, figiComposite, diff --git a/prisma/migrations/20250222084717_added_cusip_to_symbol_profile/migration.sql b/prisma/migrations/20250222084717_added_cusip_to_symbol_profile/migration.sql new file mode 100644 index 000000000..b60cebef6 --- /dev/null +++ b/prisma/migrations/20250222084717_added_cusip_to_symbol_profile/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "SymbolProfile" ADD COLUMN "cusip" TEXT; + +-- CreateIndex +CREATE INDEX "SymbolProfile_cusip_idx" ON "SymbolProfile"("cusip"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml index fbffa92c2..648c57fd5 100644 --- a/prisma/migrations/migration_lock.toml +++ b/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) +# It should be added in your version-control system (e.g., Git) provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index af9acebaf..371a3fcd8 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -174,6 +174,7 @@ model SymbolProfile { countries Json? createdAt DateTime @default(now()) currency String + cusip String? dataSource DataSource figi String? figiComposite String? @@ -196,6 +197,7 @@ model SymbolProfile { @@unique([dataSource, symbol]) @@index([assetClass]) @@index([currency]) + @@index([cusip]) @@index([dataSource]) @@index([isin]) @@index([name]) From c25b45a2b884d69420dc21648fd827cac3db27fd Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 25 Feb 2025 19:51:14 +0100 Subject: [PATCH 30/71] Release 2.141.0 (#4361) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d6f0a74..13f33d485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.141.0 - 2025-02-25 ### Added diff --git a/package-lock.json b/package-lock.json index 0fd7572e7..47bd15e2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.140.0", + "version": "2.141.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.140.0", + "version": "2.141.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 2a3881183..1921d650e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.140.0", + "version": "2.141.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 0349e17a8ef31b475386dcb14b36deaa7ee46407 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 26 Feb 2025 08:03:26 +0100 Subject: [PATCH 31/71] Feature/add security policy (#4363) * Add security policy --- SECURITY.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..528fecd44 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Reporting Security Issues + +If you discover a security vulnerability in this repository, please report it to security[at]ghostfol.io. We will acknowledge your report and provide guidance on the next steps. + +To help us resolve the issue, please include the following details: + +- A description of the vulnerability +- Steps to reproduce the vulnerability +- Affected versions of the software + +We appreciate your responsible disclosure and will work to address the issue promptly. From 168a6795359996b88fe56dddbf87f37a292689ec Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:26:51 +0100 Subject: [PATCH 32/71] Feature/extend trackinsight data enhancer by cusip (#4362) * Extend Trackinsight data enhancer by cusip * Update changelog --- CHANGELOG.md | 6 ++++++ .../data-enhancer/trackinsight/trackinsight.service.ts | 8 +++++++- .../queues/data-gathering/data-gathering.service.ts | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13f33d485..f3076d972 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Extended the _Trackinsight_ data enhancer for asset profile data by `cusip` + ## 2.141.0 - 2025-02-25 ### Added diff --git a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts index 2b8eaf2e9..32b494085 100644 --- a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts @@ -71,7 +71,13 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { return {}; }); - const isin = profile?.isin?.split(';')?.[0]; + const cusip = profile?.cusip; + + if (cusip) { + response.cusip = cusip; + } + + const isin = profile?.isins?.[0]; if (isin) { response.isin = isin; diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts index b79b2a098..b3e7de0b3 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts @@ -200,6 +200,7 @@ export class DataGatheringService { assetSubClass, countries, currency, + cusip, dataSource, figi, figiComposite, @@ -218,6 +219,7 @@ export class DataGatheringService { assetSubClass, countries, currency, + cusip, dataSource, figi, figiComposite, @@ -234,6 +236,7 @@ export class DataGatheringService { assetSubClass, countries, currency, + cusip, figi, figiComposite, figiShareClass, From 622393a7cf99366e98b6c91d9a4854bcbc12a4d2 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Fri, 28 Feb 2025 01:21:41 +0530 Subject: [PATCH 33/71] Feature/add Storybook to build process (#4340) * Add Storybook to build process * Update changelog --- CHANGELOG.md | 1 + libs/ui/project.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3076d972..87b99b790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Extended the _Trackinsight_ data enhancer for asset profile data by `cusip` +- Added _Storybook_ to the build process ## 2.141.0 - 2025-02-25 diff --git a/libs/ui/project.json b/libs/ui/project.json index 1b3f0e4e7..4c8e6c125 100644 --- a/libs/ui/project.json +++ b/libs/ui/project.json @@ -41,7 +41,7 @@ "executor": "@storybook/angular:build-storybook", "outputs": ["{options.outputDir}"], "options": { - "outputDir": "dist/storybook/ui", + "outputDir": "dist/apps/client/development/storybook", "configDir": "libs/ui/.storybook", "browserTarget": "ui:build-storybook", "compodoc": false, @@ -61,7 +61,7 @@ "executor": "@nx/web:file-server", "options": { "buildTarget": "ui:build-storybook", - "staticFilePath": "dist/storybook/ui" + "staticFilePath": "dist/storybook" }, "configurations": { "ci": { diff --git a/package.json b/package.json index 1921d650e..213de6842 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "affected:test": "nx affected:test", "analyze:client": "nx run client:build:production --stats-json && webpack-bundle-analyzer -p 1234 dist/apps/client/en/stats.json", "angular": "node --max_old_space_size=32768 ./node_modules/@angular/cli/bin/ng", - "build:production": "nx run api:copy-assets && nx run api:build:production && nx run client:copy-assets && nx run client:build:production && npm run replace-placeholders-in-build", + "build:production": "nx run api:copy-assets && nx run api:build:production && nx run client:copy-assets && nx run client:build:production && nx run ui:build-storybook && npm run replace-placeholders-in-build", "build:storybook": "nx run ui:build-storybook", "database:format-schema": "prisma format", "database:generate-typings": "prisma generate", From 2f35f7225fa70f917726f51e3101abc5745c38b4 Mon Sep 17 00:00:00 2001 From: Sayed Murtadha Ahmed Date: Thu, 27 Feb 2025 22:59:12 +0300 Subject: [PATCH 34/71] Feature/extend export by platforms (#4360) * Extend export by platforms * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/export/export.service.ts | 26 ++++++++++++++++++- .../src/lib/interfaces/export.interface.ts | 3 ++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87b99b790..2d57e73d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Extended the export functionality by the platforms - Extended the _Trackinsight_ data enhancer for asset profile data by `cusip` - Added _Storybook_ to the build process diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 219ffffda..8d7585c01 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -5,6 +5,7 @@ import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { Filter, Export } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; +import { Platform } from '@prisma/client'; @Injectable() export class ExportService { @@ -25,15 +26,37 @@ export class ExportService { userCurrency: string; userId: string; }): Promise { + const platforms: Platform[] = []; + const accounts = ( await this.accountService.accounts({ + include: { + Platform: true + }, orderBy: { name: 'asc' }, where: { userId } }) ).map( - ({ balance, comment, currency, id, isExcluded, name, platformId }) => { + ({ + balance, + comment, + currency, + id, + isExcluded, + name, + platformId, + Platform: platform + }) => { + if ( + !platforms.some(({ id: currentPlatformId }) => { + return currentPlatformId === platform.id; + }) + ) { + platforms.push(platform); + } + return { balance, comment, @@ -76,6 +99,7 @@ export class ExportService { return { meta: { date: new Date().toISOString(), version: environment.version }, accounts, + platforms, tags, activities: activities.map( ({ diff --git a/libs/common/src/lib/interfaces/export.interface.ts b/libs/common/src/lib/interfaces/export.interface.ts index 1257e50bc..14a017428 100644 --- a/libs/common/src/lib/interfaces/export.interface.ts +++ b/libs/common/src/lib/interfaces/export.interface.ts @@ -1,4 +1,4 @@ -import { Account, Order, Tag } from '@prisma/client'; +import { Account, Order, Platform, Tag } from '@prisma/client'; export interface Export { accounts: Omit[]; @@ -16,6 +16,7 @@ export interface Export { date: string; version: string; }; + platforms: Platform[]; tags: Omit[]; user: { settings: { currency: string } }; } From 2e6a1266861af84c5db4c3a27ff414a501acddd5 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 28 Feb 2025 20:58:50 +0100 Subject: [PATCH 35/71] Feature/upgrade eslint dependencies 20250119 (#4221) * Upgrade eslint dependencies * Update changelog --- CHANGELOG.md | 4 ++++ package-lock.json | 46 +++++++++++++++------------------------------- package.json | 4 ++-- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d57e73d3..89057aec9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Extended the _Trackinsight_ data enhancer for asset profile data by `cusip` - Added _Storybook_ to the build process +### Changed + +- Upgraded `eslint` dependencies + ## 2.141.0 - 2025-02-25 ### Added diff --git a/package-lock.json b/package-lock.json index 47bd15e2d..af3405261 100644 --- a/package-lock.json +++ b/package-lock.json @@ -141,9 +141,9 @@ "cypress": "6.2.1", "eslint": "9.18.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-cypress": "3.2.0", + "eslint-plugin-cypress": "4.1.0", "eslint-plugin-import": "2.31.0", - "eslint-plugin-storybook": "0.10.2", + "eslint-plugin-storybook": "0.11.2", "husky": "9.1.7", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", @@ -17087,42 +17087,26 @@ "license": "MIT" }, "node_modules/eslint-plugin-cypress": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-3.2.0.tgz", - "integrity": "sha512-HaxMz6BoU4ay+K4WrG9ZJC1NdX06FqSlAwtRDStjM0ORFT7zCNPNuRJ+kUPc17Rt2AMUBSqeD9L0zTR3uZhPpw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-4.1.0.tgz", + "integrity": "sha512-JhqkMY02mw74USwK9OFhectx3YSj6Co1NgWBxlGdKvlqiAp9vdEuQqt33DKGQFvvGS/NWtduuhWXWNnU29xDSg==", "dev": true, "license": "MIT", "dependencies": { - "globals": "^13.20.0" + "globals": "^15.11.0" }, "peerDependencies": { - "eslint": ">=7" + "eslint": ">=9" } }, "node_modules/eslint-plugin-cypress/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-cypress/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -17216,9 +17200,9 @@ } }, "node_modules/eslint-plugin-storybook": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.10.2.tgz", - "integrity": "sha512-iOrFJfyLgRLIbWDLbbs3J4yrknvIB+uiZ8KGqGOEXTL7/BGuBMZLiIU9Q4Pm/VYJrHN4JqmMtwCSrAemHL2nFg==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.11.2.tgz", + "integrity": "sha512-0Z4DUklJrC+GHjCRXa7PYfPzWC15DaVnwaOYenpgXiCEijXPZkLKCms+rHhtoRcWccP7Z8DpOOaP1gc3P9oOwg==", "dev": true, "license": "MIT", "dependencies": { @@ -17230,7 +17214,7 @@ "node": ">= 18" }, "peerDependencies": { - "eslint": ">=6" + "eslint": ">=8" } }, "node_modules/eslint-scope": { diff --git a/package.json b/package.json index 213de6842..b4caa88a6 100644 --- a/package.json +++ b/package.json @@ -187,9 +187,9 @@ "cypress": "6.2.1", "eslint": "9.18.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-cypress": "3.2.0", + "eslint-plugin-cypress": "4.1.0", "eslint-plugin-import": "2.31.0", - "eslint-plugin-storybook": "0.10.2", + "eslint-plugin-storybook": "0.11.2", "husky": "9.1.7", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", From 035306d4d8e83b64153970e48b6046af7bed5d7d Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Fri, 28 Feb 2025 21:00:02 +0100 Subject: [PATCH 36/71] Feature/add createdAt to snapshot and public portfolio endpoint response (#4350) * Add createdAt to snapshot and public portfolio endpoint response * Update changelog --------- Co-authored-by: Verbindolai Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 1 + apps/api/src/app/endpoints/public/public.controller.ts | 3 ++- apps/api/src/app/portfolio/calculator/portfolio-calculator.ts | 1 + .../src/app/portfolio/calculator/twr/portfolio-calculator.ts | 1 + apps/api/src/app/portfolio/portfolio.controller.ts | 2 ++ apps/api/src/app/portfolio/portfolio.service.ts | 3 ++- .../pages/portfolio/allocations/allocations-page.component.ts | 1 + libs/common/src/lib/interfaces/portfolio-details.interface.ts | 1 + .../responses/public-portfolio-response.interface.ts | 1 + libs/common/src/lib/models/portfolio-snapshot.ts | 2 ++ 10 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89057aec9..7124caf62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Extended the export functionality by the platforms +- Extended the portfolio snapshot in the portfolio calculator by the `createdAt` timestamp - Extended the _Trackinsight_ data enhancer for asset profile data by `cusip` - Added _Storybook_ to the build process diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts index 7488e4201..bdcd86afb 100644 --- a/apps/api/src/app/endpoints/public/public.controller.ts +++ b/apps/api/src/app/endpoints/public/public.controller.ts @@ -57,7 +57,7 @@ export class PublicController { } const [ - { holdings, markets }, + { createdAt, holdings, markets }, { performance: performance1d }, { performance: performanceMax }, { performance: performanceYtd } @@ -81,6 +81,7 @@ export class PublicController { }); const publicPortfolioResponse: PublicPortfolioResponse = { + createdAt, hasDetails, markets, alias: access.alias, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index e9c4fdcce..54d80a955 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -176,6 +176,7 @@ export abstract class PortfolioCalculator { if (!transactionPoints.length) { return { activitiesCount: 0, + createdAt: new Date(), currentValueInBaseCurrency: new Big(0), errors: [], hasErrors: false, diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts index 209a0efd5..059b85441 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts @@ -104,6 +104,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { activitiesCount: this.activities.filter(({ type }) => { return ['BUY', 'SELL'].includes(type); }).length, + createdAt: new Date(), errors: [], historicalData: [], totalLiabilitiesWithCurrencyEffect: new Big(0), diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 797d0449a..c3e46d50d 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -105,6 +105,7 @@ export class PortfolioController { const { accounts, + createdAt, hasErrors, holdings, markets, @@ -233,6 +234,7 @@ export class PortfolioController { return { accounts, + createdAt, hasError, holdings, platforms, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 811c59f9d..d4dc42d91 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -376,7 +376,7 @@ export class PortfolioService { currency: userCurrency }); - const { currentValueInBaseCurrency, hasErrors, positions } = + const { createdAt, currentValueInBaseCurrency, hasErrors, positions } = await portfolioCalculator.getSnapshot(); const cashDetails = await this.accountService.getCashDetails({ @@ -617,6 +617,7 @@ export class PortfolioService { return { accounts, + createdAt, hasErrors, holdings, markets, diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index 41961edd3..54ea88548 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -260,6 +260,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { this.platforms = {}; this.portfolioDetails = { accounts: {}, + createdAt: undefined, holdings: {}, platforms: {}, summary: undefined diff --git a/libs/common/src/lib/interfaces/portfolio-details.interface.ts b/libs/common/src/lib/interfaces/portfolio-details.interface.ts index e455f73ca..746736f6b 100644 --- a/libs/common/src/lib/interfaces/portfolio-details.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-details.interface.ts @@ -14,6 +14,7 @@ export interface PortfolioDetails { valueInPercentage?: number; }; }; + createdAt: Date; holdings: { [symbol: string]: PortfolioPosition }; markets?: { [key in Market]: { 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 dc6e57587..7a98e3c8d 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 @@ -32,6 +32,7 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 { } interface PublicPortfolioResponseV1 { + createdAt: Date; performance: { '1d': { relativeChange: number; diff --git a/libs/common/src/lib/models/portfolio-snapshot.ts b/libs/common/src/lib/models/portfolio-snapshot.ts index d0c4c66e0..e30585b82 100644 --- a/libs/common/src/lib/models/portfolio-snapshot.ts +++ b/libs/common/src/lib/models/portfolio-snapshot.ts @@ -11,6 +11,8 @@ import { Transform, Type } from 'class-transformer'; export class PortfolioSnapshot { activitiesCount: number; + createdAt: Date; + @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) currentValueInBaseCurrency: Big; From b3954b047faa67fbffd0b845def00b1caf9a4461 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 28 Feb 2025 21:02:20 +0100 Subject: [PATCH 37/71] Release 2.142.0 (#4373) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7124caf62..0dca2be52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.142.0 - 2025-02-28 ### Added diff --git a/package-lock.json b/package-lock.json index af3405261..601c8f42a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.141.0", + "version": "2.142.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.141.0", + "version": "2.142.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index b4caa88a6..d49ce5037 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.141.0", + "version": "2.142.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From a8d124846116b0d261eddaca9e9a7b0756666720 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Mar 2025 13:14:39 +0100 Subject: [PATCH 38/71] Feature/improve symbol lookup in Trackinsight service (#4377) * Improve symbol lookup for EXCHANGE:SYMBOL pattern * Update changelog --- CHANGELOG.md | 6 ++++++ .../data-enhancer/trackinsight/trackinsight.service.ts | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dca2be52..a0610a839 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data + ## 2.142.0 - 2025-02-28 ### Added diff --git a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts index 32b494085..8b885c013 100644 --- a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts @@ -192,7 +192,10 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface { .then((jsonRes) => { if ( jsonRes['results']?.['count'] === 1 || - jsonRes['results']?.['docs']?.[0]?.['ticker'] === symbol + // Allow exact match + jsonRes['results']?.['docs']?.[0]?.['ticker'] === symbol || + // Allow EXCHANGE:SYMBOL + jsonRes['results']?.['docs']?.[0]?.['ticker']?.endsWith(`:${symbol}`) ) { return jsonRes['results']['docs'][0]['ticker']; } From 6cdcf9622e79102c95702850872df5596d366f8d Mon Sep 17 00:00:00 2001 From: Matt Fiddaman Date: Sat, 1 Mar 2025 14:16:21 +0000 Subject: [PATCH 39/71] Bugfix/handle exception in benchmark service related to unnamed asset profiles (#4355) * Handle exception in benchmark service related to unnamed asset profiles * Update changelog --- CHANGELOG.md | 4 ++++ apps/api/src/services/benchmark/benchmark.service.ts | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0610a839..c518d92f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data +### Fixed + +- Handled an exception in the benchmark service related to unnamed asset profiles + ## 2.142.0 - 2025-02-28 ### Added diff --git a/apps/api/src/services/benchmark/benchmark.service.ts b/apps/api/src/services/benchmark/benchmark.service.ts index 57105da71..95cb9e5d2 100644 --- a/apps/api/src/services/benchmark/benchmark.service.ts +++ b/apps/api/src/services/benchmark/benchmark.service.ts @@ -133,7 +133,9 @@ export class BenchmarkService { symbol }; }) - .sort((a, b) => a.name.localeCompare(b.name)); + .sort((a, b) => { + return a.name?.localeCompare(b?.name) ?? 0; + }); } public async addBenchmark({ From 8f4f29571bc71eadac8eb1599de35270e9c2c4f4 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Mar 2025 09:10:51 +0100 Subject: [PATCH 40/71] Bugfix/fix export functionality of platforms (#4379) * Fix export functionality of platforms * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/export/export.service.ts | 16 ++++++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c518d92f0..e1adcd3ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Handled an exception in the export functionality related to platforms - Handled an exception in the benchmark service related to unnamed asset profiles ## 2.142.0 - 2025-02-28 diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 8d7585c01..c6c24d6af 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -26,7 +26,7 @@ export class ExportService { userCurrency: string; userId: string; }): Promise { - const platforms: Platform[] = []; + const platformsMap: { [platformId: string]: Platform } = {}; const accounts = ( await this.accountService.accounts({ @@ -46,15 +46,11 @@ export class ExportService { id, isExcluded, name, - platformId, - Platform: platform + Platform: platform, + platformId }) => { - if ( - !platforms.some(({ id: currentPlatformId }) => { - return currentPlatformId === platform.id; - }) - ) { - platforms.push(platform); + if (platformId) { + platformsMap[platformId] = platform; } return { @@ -99,7 +95,7 @@ export class ExportService { return { meta: { date: new Date().toISOString(), version: environment.version }, accounts, - platforms, + platforms: Object.values(platformsMap), tags, activities: activities.map( ({ From 8b353fbf66aed77eef2c96c4660b0c0477fc14fa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:01:36 +0100 Subject: [PATCH 41/71] Feature/introduce Promise.all() in getPerformance() of portfolio service (#4381) * Introduce Promise.all() * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/portfolio/portfolio.service.ts | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1adcd3ba..292232754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Optimized the asynchronous operations using `Promise.all()` in the portfolio service (`getPerformance`) - Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data ### Fixed diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d4dc42d91..ce03c8024 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1081,19 +1081,18 @@ export class PortfolioService { const user = await this.userService.user({ id: userId }); const userCurrency = this.getUserCurrency(user); - const accountBalanceItems = - await this.accountBalanceService.getAccountBalanceItems({ + const [accountBalanceItems, { activities }] = await Promise.all([ + this.accountBalanceService.getAccountBalanceItems({ filters, userId, userCurrency - }); - - const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + }), + this.orderService.getOrdersForPortfolioCalculator({ filters, userCurrency, userId - }); + }) + ]); if (accountBalanceItems.length === 0 && activities.length === 0) { return { From 51f0ecbfc10828da62af68d9091719570fa0632a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:03:11 +0100 Subject: [PATCH 42/71] Feature/add LinkedIn page to about page and footer (#4378) * Add LinkedIn page * Update changelog --- CHANGELOG.md | 5 +++++ apps/client/src/app/app.component.html | 9 +++++++++ .../about/overview/about-overview-page.html | 20 +++++++++++++------ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 292232754..a8d30ab33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added the Ghostfolio _LinkedIn_ page to the about page +- Added the Ghostfolio _LinkedIn_ page to the footer + ### Changed - Optimized the asynchronous operations using `Promise.all()` in the portfolio service (`getPerformance`) diff --git a/apps/client/src/app/app.component.html b/apps/client/src/app/app.component.html index c6734d1b4..ab188dfcb 100644 --- a/apps/client/src/app/app.component.html +++ b/apps/client/src/app/app.component.html @@ -129,6 +129,15 @@ >GitHub +
  • + LinkedIn +
  • .

    + + + - + - +

    @if (hasPermissionForSubscription) { From 5fa7b7a2312d4697bf98c046425f4da80025e37c Mon Sep 17 00:00:00 2001 From: Ken Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Mon, 3 Mar 2025 00:19:42 +0800 Subject: [PATCH 43/71] Task/upgrade to color version 5.0 (#4383) * chore(deps): bump color from 4.2.3 to 5.0.0 * chore(deps-dev): remove @types/color * feat(ui): change color imports * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 1 + .../fire-calculator.component.ts | 2 +- .../portfolio-proportion-chart.component.ts | 2 +- package-lock.json | 99 +++++++++---------- package.json | 3 +- 5 files changed, 48 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8d30ab33..859304338 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Optimized the asynchronous operations using `Promise.all()` in the portfolio service (`getPerformance`) - Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data +- Upgraded `color` from version `4.2.3` to `5.0.0` ### Fixed diff --git a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts index f8ce3dd50..64fbe1b74 100644 --- a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts +++ b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -41,7 +41,7 @@ import { Tooltip } from 'chart.js'; import 'chartjs-adapter-date-fns'; -import * as Color from 'color'; +import Color from 'color'; import { add, addYears, diff --git a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts index 6319c3cd7..cc3c40d32 100644 --- a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts +++ b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -29,7 +29,7 @@ import { ArcElement } from 'chart.js'; import { DoughnutController } from 'chart.js'; import { Chart } from 'chart.js'; import ChartDataLabels from 'chartjs-plugin-datalabels'; -import * as Color from 'color'; +import Color from 'color'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; const { diff --git a/package-lock.json b/package-lock.json index 601c8f42a..c4392b359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,7 @@ "cheerio": "1.0.0", "class-transformer": "0.5.1", "class-validator": "0.14.1", - "color": "4.2.3", + "color": "5.0.0", "countries-and-timezones": "3.7.2", "countries-list": "3.1.1", "countup.js": "2.8.0", @@ -128,7 +128,6 @@ "@trivago/prettier-plugin-sort-imports": "5.2.2", "@types/big.js": "6.2.2", "@types/cache-manager": "4.0.6", - "@types/color": "4.2.0", "@types/google-spreadsheet": "3.1.5", "@types/jest": "29.5.13", "@types/lodash": "4.17.7", @@ -10705,33 +10704,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/color": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/color/-/color-4.2.0.tgz", - "integrity": "sha512-6+xrIRImMtGAL2X3qYkd02Mgs+gFGs+WsK0b7VVMaO4mYRISwyTjcqNrO0mNSmYEoq++rSLDB2F5HDNmqfOe+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/color-convert": "*" - } - }, - "node_modules/@types/color-convert": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.4.tgz", - "integrity": "sha512-Ub1MmDdyZ7mX//g25uBAoH/mWGd9swVbt8BseymnaE18SU4po/PjmCrHxqIIRjBo3hV/vh1KGr0eMxUhp+t+dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/color-name": "^1.1.0" - } - }, - "node_modules/@types/color-name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.5.tgz", - "integrity": "sha512-j2K5UJqGTxeesj6oQuGpMgifpT5k9HprgQd8D1Y0lOFqKHl3PJu5GMeS4Y5EgjS55AE6OQxf8mPED9uaGbf4Cg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -14304,16 +14276,16 @@ "license": "MIT" }, "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.0.tgz", + "integrity": "sha512-16BlyiuyLq3MLxpRWyOTiWsO3ii/eLQLJUQXBSNcxMBBSnyt1ee9YUdaozQp03ifwm5woztEZGDbk9RGVuCsdw==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" + "color-convert": "^3.0.1", + "color-string": "^2.0.0" }, "engines": { - "node": ">=12.5.0" + "node": ">=18" } }, "node_modules/color-convert": { @@ -14335,13 +14307,45 @@ "license": "MIT" }, "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.0.1.tgz", + "integrity": "sha512-5z9FbYTZPAo8iKsNEqRNv+OlpBbDcoE+SY9GjLfDUHEfcNNV7tS9eSAlFHEaub/r5tBL9LtskAeq1l9SaoZ5tQ==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.0.tgz", + "integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.0.1.tgz", + "integrity": "sha512-5kQah2eolfQV7HCrxtsBBArPfT5dwaKYMCXeMQsdRO7ihTO/cuNLGjd50ITCDn+ZU/YbS0Go64SjP9154eopxg==", "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.0.tgz", + "integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==", + "license": "MIT", + "engines": { + "node": ">=12.20" } }, "node_modules/colord": { @@ -28927,21 +28931,6 @@ "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==", "license": "ISC" }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" - }, "node_modules/sirv": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", diff --git a/package.json b/package.json index d49ce5037..144258f26 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "cheerio": "1.0.0", "class-transformer": "0.5.1", "class-validator": "0.14.1", - "color": "4.2.3", + "color": "5.0.0", "countries-and-timezones": "3.7.2", "countries-list": "3.1.1", "countup.js": "2.8.0", @@ -174,7 +174,6 @@ "@trivago/prettier-plugin-sort-imports": "5.2.2", "@types/big.js": "6.2.2", "@types/cache-manager": "4.0.6", - "@types/color": "4.2.0", "@types/google-spreadsheet": "3.1.5", "@types/jest": "29.5.13", "@types/lodash": "4.17.7", From 7def72581557f2fe80dd33837a8d941150b7d67a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:23:29 +0100 Subject: [PATCH 44/71] Update locales (#4384) Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 4 ++-- apps/client/src/locales/messages.de.xlf | 4 ++-- apps/client/src/locales/messages.es.xlf | 4 ++-- apps/client/src/locales/messages.fr.xlf | 4 ++-- apps/client/src/locales/messages.it.xlf | 4 ++-- apps/client/src/locales/messages.nl.xlf | 4 ++-- apps/client/src/locales/messages.pl.xlf | 4 ++-- apps/client/src/locales/messages.pt.xlf | 4 ++-- apps/client/src/locales/messages.tr.xlf | 4 ++-- apps/client/src/locales/messages.uk.xlf | 4 ++-- apps/client/src/locales/messages.xlf | 4 ++-- apps/client/src/locales/messages.zh.xlf | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index a36fb152f..d5356fe0f 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -250,7 +250,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 @@ -358,7 +358,7 @@ El risc d’assumir pèrdues en les inversions és substancial. No és recomanable invertir diners que pugui necessitar a curt termini. apps/client/src/app/app.component.html - 205 + 214 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 3983ca586..1907bbc3a 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -22,7 +22,7 @@ Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches du kurzfristig benötigst. apps/client/src/app/app.component.html - 205 + 214 @@ -4162,7 +4162,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index e41708851..98690ec76 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -23,7 +23,7 @@ El riesgo de pérdida en trading puede ser sustancial. No es aconsejable invertir dinero que puedas necesitar a corto plazo. apps/client/src/app/app.component.html - 205 + 214 @@ -4163,7 +4163,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index aa0dd2891..840aa3cb1 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -6,7 +6,7 @@ Le risque de perte en investissant peut être important. Il est déconseillé d’investir de l’argent dont vous pourriez avoir besoin à court terme. apps/client/src/app/app.component.html - 205 + 214 @@ -4162,7 +4162,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index a17749690..f558f7c3e 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -23,7 +23,7 @@ Il rischio di perdita nel trading può essere notevole. Non è consigliabile investire denaro di cui potresti avere bisogno a breve termine. apps/client/src/app/app.component.html - 205 + 214 @@ -4163,7 +4163,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index d8609b1b5..f3850ee9a 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -22,7 +22,7 @@ Het risico op verlies bij handelen kan aanzienlijk zijn. Het is niet aan te raden om geld te investeren dat je misschien op korte termijn nodig heeft. apps/client/src/app/app.component.html - 205 + 214 @@ -4162,7 +4162,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index c53b6177f..2e3596f2c 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -667,7 +667,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 @@ -775,7 +775,7 @@ Ryzyko strat na rynku może być znaczne. Nie jest zalecane inwestowanie pieniędzy, które mogą być potrzebne w krótkim okresie. apps/client/src/app/app.component.html - 205 + 214 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index e2a79168a..751426dbf 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -6,7 +6,7 @@ O risco de perda em investimentos pode ser substancial. Não é aconselhável investir dinheiro que possa vir a precisar a curto prazo. apps/client/src/app/app.component.html - 205 + 214 @@ -4162,7 +4162,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 35415106f..b0f601282 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -643,7 +643,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 @@ -751,7 +751,7 @@ Alım satımda kayıp riski büyük boyutta olabilir. Kısa vadede ihtiyaç duyabileceğiniz parayla yatırım yapmak tavsiye edilmez. apps/client/src/app/app.component.html - 205 + 214 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index e013a621a..3803fb73a 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -250,7 +250,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 @@ -358,7 +358,7 @@ Ризик втрат у торгівлі може бути суттєвим. Не рекомендується інвестувати гроші, які можуть знадобитися в короткостроковій перспективі. apps/client/src/app/app.component.html - 205 + 214 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 7d93b392f..2c540010f 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -649,7 +649,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 @@ -752,7 +752,7 @@ The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. apps/client/src/app/app.component.html - 205 + 214 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 10fc585a8..4b03c7783 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -668,7 +668,7 @@ apps/client/src/app/pages/about/overview/about-overview-page.html - 146 + 154 @@ -776,7 +776,7 @@ 交易损失的风险可能很大。不建议将短期内可能需要的资金进行投资。 apps/client/src/app/app.component.html - 205 + 214 From 3b68400a23233c7ed649055b344754da91070b00 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:26:16 +0100 Subject: [PATCH 45/71] Feature/upgrade prisma to version 6.4.1 (#4380) * Upgrade prisma to version 6.4.1 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 70 ++++++++++++++++++++++++----------------------- package.json | 4 +-- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 859304338..878ba40e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Optimized the asynchronous operations using `Promise.all()` in the portfolio service (`getPerformance`) - Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data - Upgraded `color` from version `4.2.3` to `5.0.0` +- Upgraded `prisma` from version `6.3.0` to `6.4.1` ### Fixed diff --git a/package-lock.json b/package-lock.json index c4392b359..af8467d7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "@nestjs/platform-express": "10.4.15", "@nestjs/schedule": "4.1.2", "@nestjs/serve-static": "4.0.2", - "@prisma/client": "6.3.0", + "@prisma/client": "6.4.1", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@stripe/stripe-js": "5.4.0", @@ -150,7 +150,7 @@ "nx": "20.3.2", "prettier": "3.5.1", "prettier-plugin-organize-attributes": "1.0.0", - "prisma": "6.3.0", + "prisma": "6.4.1", "react": "18.2.0", "react-dom": "18.2.0", "replace-in-file": "8.3.0", @@ -8846,9 +8846,9 @@ "license": "MIT" }, "node_modules/@prisma/client": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.3.0.tgz", - "integrity": "sha512-BY3Fi28PUSk447Bpv22LhZp4HgNPo7NsEN+EteM1CLDnLjig5863jpW+3c3HHLFmml+nB/eJv1CjSriFZ8z7Cg==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.4.1.tgz", + "integrity": "sha512-A7Mwx44+GVZVexT5e2GF/WcKkEkNNKbgr059xpr5mn+oUm2ZW1svhe+0TRNBwCdzhfIZ+q23jEgsNPvKD9u+6g==", "hasInstallScript": true, "license": "Apache-2.0", "engines": { @@ -8868,53 +8868,53 @@ } }, "node_modules/@prisma/debug": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.3.0.tgz", - "integrity": "sha512-m1lQv//0Rc5RG8TBpNUuLCxC35Ghi5XfpPmL83Gh04/GICHD2J5H2ndMlaljrUNaQDF9dOxIuFAYP1rE9wkXkg==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.4.1.tgz", + "integrity": "sha512-Q9xk6yjEGIThjSD8zZegxd5tBRNHYd13GOIG0nLsanbTXATiPXCLyvlYEfvbR2ft6dlRsziQXfQGxAgv7zcMUA==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.3.0.tgz", - "integrity": "sha512-RXqYhlZb9sx/xkUfYIZuEPn7sT0WgTxNOuEYQ7AGw3IMpP9QGVEDVsluc/GcNkM8NTJszeqk8AplJzI9lm7Jxw==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.4.1.tgz", + "integrity": "sha512-KldENzMHtKYwsOSLThghOIdXOBEsfDuGSrxAZjMnimBiDKd3AE4JQ+Kv+gBD/x77WoV9xIPf25GXMWffXZ17BA==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.3.0", - "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", - "@prisma/fetch-engine": "6.3.0", - "@prisma/get-platform": "6.3.0" + "@prisma/debug": "6.4.1", + "@prisma/engines-version": "6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d", + "@prisma/fetch-engine": "6.4.1", + "@prisma/get-platform": "6.4.1" } }, "node_modules/@prisma/engines-version": { - "version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0.tgz", - "integrity": "sha512-R/ZcMuaWZT2UBmgX3Ko6PAV3f8//ZzsjRIG1eKqp3f2rqEqVtCv+mtzuH2rBPUC9ujJ5kCb9wwpxeyCkLcHVyA==", + "version": "6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d.tgz", + "integrity": "sha512-Xq54qw55vaCGrGgIJqyDwOq0TtjZPJEWsbQAHugk99hpDf2jcEeQhUcF+yzEsSqegBaDNLA4IC8Nn34sXmkiTQ==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.3.0.tgz", - "integrity": "sha512-GBy0iT4f1mH31ePzfcpVSUa7JLRTeq4914FG2vR3LqDwRweSm4ja1o5flGDz+eVIa/BNYfkBvRRxv4D6ve6Eew==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.4.1.tgz", + "integrity": "sha512-uZ5hVeTmDspx7KcaRCNoXmcReOD+84nwlO2oFvQPRQh9xiFYnnUKDz7l9bLxp8t4+25CsaNlgrgilXKSQwrIGQ==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.3.0", - "@prisma/engines-version": "6.3.0-17.acc0b9dd43eb689cbd20c9470515d719db10d0b0", - "@prisma/get-platform": "6.3.0" + "@prisma/debug": "6.4.1", + "@prisma/engines-version": "6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d", + "@prisma/get-platform": "6.4.1" } }, "node_modules/@prisma/get-platform": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.3.0.tgz", - "integrity": "sha512-V8zZ1d0xfyi6FjpNP4AcYuwSpGcdmu35OXWnTPm8IW594PYALzKXHwIa9+o0f+Lo9AecFWrwrwaoYe56UNfTtQ==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.4.1.tgz", + "integrity": "sha512-gXqZaDI5scDkBF8oza7fOD3Q3QMD0e0rBynlzDDZdTWbWmzjuW58PRZtj+jkvKje2+ZigCWkH8SsWZAsH6q1Yw==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "6.3.0" + "@prisma/debug": "6.4.1" } }, "node_modules/@redis/bloom": { @@ -16805,7 +16805,7 @@ "version": "0.24.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -16846,7 +16846,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "debug": "^4.3.4" @@ -27173,14 +27173,16 @@ } }, "node_modules/prisma": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.3.0.tgz", - "integrity": "sha512-y+Zh3Qg+xGCWyyrNUUNaFW/OltaV/yXYuTa0WRgYkz5LGyifmAsgpv94I47+qGRocZrMGcbF2A/78/oO2zgifA==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.4.1.tgz", + "integrity": "sha512-q2uJkgXnua/jj66mk6P9bX/zgYJFI/jn4Yp0aS6SPRrjH/n6VyOV7RDe1vHD0DX8Aanx4MvgmUPPoYnR6MJnPg==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "6.3.0" + "@prisma/engines": "6.4.1", + "esbuild": ">=0.12 <1", + "esbuild-register": "3.6.0" }, "bin": { "prisma": "build/index.js" diff --git a/package.json b/package.json index 144258f26..f7d9451db 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "@nestjs/platform-express": "10.4.15", "@nestjs/schedule": "4.1.2", "@nestjs/serve-static": "4.0.2", - "@prisma/client": "6.3.0", + "@prisma/client": "6.4.1", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@stripe/stripe-js": "5.4.0", @@ -196,7 +196,7 @@ "nx": "20.3.2", "prettier": "3.5.1", "prettier-plugin-organize-attributes": "1.0.0", - "prisma": "6.3.0", + "prisma": "6.4.1", "react": "18.2.0", "react-dom": "18.2.0", "replace-in-file": "8.3.0", From f63d171678be6a107d857c9071f286805d2b59b2 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:27:45 +0100 Subject: [PATCH 46/71] Feature/improve usability of no activities info (#4382) * Improve usability * Update changelog --- CHANGELOG.md | 2 ++ .../home-holdings/home-holdings.html | 1 - .../home-overview/home-overview.html | 2 +- .../activities/activities-page.component.ts | 30 ++++++++++++++++++- .../portfolio/activities/activities-page.html | 4 ++- .../holdings-table.component.html | 8 ----- .../holdings-table.component.ts | 3 -- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 878ba40e8..ac3c45915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Optimized the asynchronous operations using `Promise.all()` in the portfolio service (`getPerformance`) - Improved the symbol lookup in the _Trackinsight_ data enhancer for asset profile data +- Removed the no transactions info component from the holdings table on the home page +- Refactored the show condition of the step by step introduction for new users using the activities count - Upgraded `color` from version `4.2.3` to `5.0.0` - Upgraded `prisma` from version `6.3.0` to `6.4.1` diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index abbc93b3d..f981e50a1 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -48,7 +48,6 @@ - @if (hasPermissionToCreateOrder && historicalDataItems?.length === 0) { + @if (hasPermissionToCreateOrder && user?.activitiesCount === 0) {

    Welcome to Ghostfolio

    diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts index 91254e002..5f5f7cea9 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts @@ -125,7 +125,10 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { this.dataSource = new MatTableDataSource(activities); this.totalItems = count; - if (this.hasPermissionToCreateActivity && this.totalItems <= 0) { + if ( + this.hasPermissionToCreateActivity && + this.user?.activitiesCount === 0 + ) { this.router.navigate([], { queryParams: { createDialog: true } }); } @@ -160,6 +163,11 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { }) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + this.fetchActivities(); }); } @@ -169,6 +177,11 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { .deleteActivity(aId) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + this.fetchActivities(); }); } @@ -230,6 +243,11 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + this.fetchActivities(); }); } @@ -248,6 +266,11 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + this.fetchActivities(); }); } @@ -333,6 +356,11 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { if (transaction) { this.dataService.postOrder(transaction).subscribe({ next: () => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + this.fetchActivities(); } }); diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.html b/apps/client/src/app/pages/portfolio/activities/activities-page.html index c06f7dd75..99eb16386 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.html +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -6,7 +6,9 @@ [baseCurrency]="user?.settings?.baseCurrency" [dataSource]="dataSource" [deviceType]="deviceType" - [hasPermissionToCreateActivity]="hasPermissionToCreateActivity" + [hasPermissionToCreateActivity]=" + hasPermissionToCreateActivity && user?.activitiesCount === 0 + " [hasPermissionToDeleteActivity]="hasPermissionToDeleteActivity" [hasPermissionToExportActivities]="!hasImpersonationId" [locale]="user?.settings?.locale" diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index 5e4526fdc..dde103077 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -198,11 +198,3 @@
    } - -@if ( - dataSource.data.length === 0 && hasPermissionToCreateActivity && !isLoading -) { -
    - -
    -} diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 14382f420..802cdc69a 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -5,7 +5,6 @@ import { AssetProfileIdentifier, PortfolioPosition } from '@ghostfolio/common/interfaces'; -import { GfNoTransactionsInfoComponent } from '@ghostfolio/ui/no-transactions-info'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; @@ -34,7 +33,6 @@ import { Subject, Subscription } from 'rxjs'; imports: [ CommonModule, GfAssetProfileIconComponent, - GfNoTransactionsInfoComponent, GfSymbolModule, GfValueComponent, MatButtonModule, @@ -52,7 +50,6 @@ import { Subject, Subscription } from 'rxjs'; export class GfHoldingsTableComponent implements OnChanges, OnDestroy { @Input() baseCurrency: string; @Input() deviceType: string; - @Input() hasPermissionToCreateActivity: boolean; @Input() hasPermissionToOpenDetails = true; @Input() hasPermissionToShowValues = true; @Input() holdings: PortfolioPosition[]; From f3764f32bbca8f98b85ee71c9a255c1d00258ffb Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:32:09 +0100 Subject: [PATCH 47/71] Release 2.143.0 (#4386) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac3c45915..e11471a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.143.0 - 2025-03-02 ### Added diff --git a/package-lock.json b/package-lock.json index af8467d7e..11e1b6ebd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.142.0", + "version": "2.143.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.142.0", + "version": "2.143.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index f7d9451db..9df5e1172 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.142.0", + "version": "2.143.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 533481fc56affa8ef96ab077b03fbb9e0a7d383d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Mar 2025 18:08:43 +0100 Subject: [PATCH 48/71] Update locales (#4385) Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 2 +- apps/client/src/locales/messages.de.xlf | 2 +- apps/client/src/locales/messages.es.xlf | 2 +- apps/client/src/locales/messages.fr.xlf | 2 +- apps/client/src/locales/messages.it.xlf | 2 +- apps/client/src/locales/messages.nl.xlf | 2 +- apps/client/src/locales/messages.pl.xlf | 2 +- apps/client/src/locales/messages.pt.xlf | 2 +- apps/client/src/locales/messages.tr.xlf | 2 +- apps/client/src/locales/messages.uk.xlf | 2 +- apps/client/src/locales/messages.xlf | 2 +- apps/client/src/locales/messages.zh.xlf | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index d5356fe0f..ec0121ab5 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -2659,7 +2659,7 @@ Gestionar Activitats apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 1907bbc3a..0bd543de9 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -1050,7 +1050,7 @@ Aktivitäten verwalten apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 98690ec76..da0c0fb5c 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -1051,7 +1051,7 @@ Gestión de las operaciones apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 840aa3cb1..77224f1c9 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1366,7 +1366,7 @@ Gérer les Activités apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index f558f7c3e..80ca9ced7 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -1051,7 +1051,7 @@ Gestione delle attività apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index f3850ee9a..8beeae481 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -1050,7 +1050,7 @@ Activiteiten beheren apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 2e3596f2c..d2001157e 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -2315,7 +2315,7 @@ Zarządzaj Aktywnościami apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 751426dbf..10c72e589 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -1238,7 +1238,7 @@ Gerir Atividades apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index b0f601282..ca2c9f99c 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -2167,7 +2167,7 @@ İşlemleri Yönet apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index 3803fb73a..a6146f4b2 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -2787,7 +2787,7 @@ Керування діяльністю apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 2c540010f..cb3bc15b3 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -2177,7 +2177,7 @@ Manage Activities apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 4b03c7783..37db811ae 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -2324,7 +2324,7 @@ 管理活动 apps/client/src/app/components/home-holdings/home-holdings.html - 63 + 62 From d923e6f2e2f7e864c143502468dcdc125a50facc Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 3 Mar 2025 21:57:39 +0100 Subject: [PATCH 49/71] Feature/harmonize section names in bug report template (#4319) * Harmonize section names --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1fabe2f48..329a9a5a3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -26,7 +26,7 @@ Thank you for your understanding and cooperation! 2. 3. -**Expected behavior** +**Expected Behavior** @@ -48,6 +48,6 @@ Thank you for your understanding and cooperation! - Browser - OS -**Additional context** +**Additional Context** From 3a09996ca1432b2a33eaa7a335ddabe4360b0fc9 Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Wed, 5 Mar 2025 20:25:32 +0100 Subject: [PATCH 50/71] Bugfix/fix functionality to delete asset profile of custom currency (#4354) * Fix functionality to delete asset profile of custom currency * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.service.ts | 21 ++++++++++++++++++- .../admin-market-data.service.ts | 4 +++- libs/common/src/lib/helper.ts | 10 +++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e11471a63..f2b076369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Handled an exception in the export functionality related to platforms - Handled an exception in the benchmark service related to unnamed asset profiles +- Fixed the functionality to delete an asset profile of a custom currency ## 2.142.0 - 2025-02-28 diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index ee79059f9..7f2b0da5a 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -109,7 +109,26 @@ export class AdminService { symbol }: AssetProfileIdentifier) { await this.marketDataService.deleteMany({ dataSource, symbol }); - await this.symbolProfileService.delete({ dataSource, symbol }); + + const currency = getCurrencyFromSymbol(symbol); + const customCurrencies = (await this.propertyService.getByKey( + PROPERTY_CURRENCIES + )) as string[]; + + if (customCurrencies.includes(currency)) { + const updatedCustomCurrencies = customCurrencies.filter( + (customCurrency) => { + return customCurrency !== currency; + } + ); + + await this.putSetting( + PROPERTY_CURRENCIES, + JSON.stringify(updatedCustomCurrencies) + ); + } else { + await this.symbolProfileService.delete({ dataSource, symbol }); + } } public async get(): Promise { diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts index 86965cd8a..0e2cb7ef3 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts @@ -4,7 +4,8 @@ import { AdminService } from '@ghostfolio/client/services/admin.service'; import { ghostfolioScraperApiSymbolPrefix } from '@ghostfolio/common/config'; import { getCurrencyFromSymbol, - isDerivedCurrency + isDerivedCurrency, + isRootCurrency } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, @@ -77,6 +78,7 @@ export class AdminMarketDataService { activitiesCount === 0 && !isBenchmark && !isDerivedCurrency(getCurrencyFromSymbol(symbol)) && + !isRootCurrency(getCurrencyFromSymbol(symbol)) && !symbol.startsWith(ghostfolioScraperApiSymbolPrefix) ); } diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index bd0c74189..e5104a991 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -354,6 +354,16 @@ export function isDerivedCurrency(aCurrency: string) { }); } +export function isRootCurrency(aCurrency: string) { + if (aCurrency === 'USD') { + return true; + } + + return DERIVED_CURRENCIES.find(({ rootCurrency }) => { + return rootCurrency === aCurrency; + }); +} + export function parseDate(date: string): Date { if (!date) { return undefined; From ddb50295b262d1123c808cdc2db47923d3a993c2 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 5 Mar 2025 20:54:32 +0100 Subject: [PATCH 51/71] Bugfix/fix changelog (#4400) * Fix changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2b076369..44b6c720a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Fixed the functionality to delete an asset profile of a custom currency in the admin control panel + ## 2.143.0 - 2025-03-02 ### Added @@ -25,7 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Handled an exception in the export functionality related to platforms - Handled an exception in the benchmark service related to unnamed asset profiles -- Fixed the functionality to delete an asset profile of a custom currency ## 2.142.0 - 2025-02-28 From 12ae54e01bc359239708cdd300d7072ff15ee7d7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 6 Mar 2025 06:30:10 +0100 Subject: [PATCH 52/71] Bugfix/fix activities import on non-empty activities page (#4398) * Add missing import functionality * Update changelog --- CHANGELOG.md | 1 + .../src/app/pages/portfolio/activities/activities-page.html | 5 ++--- .../src/lib/activities-table/activities-table.component.html | 5 ++++- .../src/lib/activities-table/activities-table.component.ts | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44b6c720a..570112db2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed the missing import functionality on the non-empty activities page - Fixed the functionality to delete an asset profile of a custom currency in the admin control panel ## 2.143.0 - 2025-03-02 diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.html b/apps/client/src/app/pages/portfolio/activities/activities-page.html index 99eb16386..80ad71b79 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.html +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -6,9 +6,8 @@ [baseCurrency]="user?.settings?.baseCurrency" [dataSource]="dataSource" [deviceType]="deviceType" - [hasPermissionToCreateActivity]=" - hasPermissionToCreateActivity && user?.activitiesCount === 0 - " + [hasActivities]="user?.activitiesCount > 0" + [hasPermissionToCreateActivity]="hasPermissionToCreateActivity" [hasPermissionToDeleteActivity]="hasPermissionToDeleteActivity" [hasPermissionToExportActivities]="!hasImpersonationId" [locale]="user?.settings?.locale" diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index 4fdc41c59..e5b33efd2 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -500,7 +500,10 @@ /> @if ( - dataSource?.data.length === 0 && hasPermissionToCreateActivity && !isLoading + !hasActivities && + dataSource?.data.length === 0 && + hasPermissionToCreateActivity && + !isLoading ) {
    diff --git a/libs/ui/src/lib/activities-table/activities-table.component.ts b/libs/ui/src/lib/activities-table/activities-table.component.ts index 01b4c6ead..8e5a44a50 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -76,6 +76,7 @@ export class GfActivitiesTableComponent @Input() baseCurrency: string; @Input() dataSource: MatTableDataSource; @Input() deviceType: string; + @Input() hasActivities: boolean; @Input() hasPermissionToCreateActivity: boolean; @Input() hasPermissionToDeleteActivity: boolean; @Input() hasPermissionToExportActivities: boolean; From 72f1246b39a788aa12615ea6447818c7add92e73 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 08:11:56 +0100 Subject: [PATCH 53/71] Feature/update locales (#4399) * Update locales --- Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 10 +++++----- apps/client/src/locales/messages.de.xlf | 10 +++++----- apps/client/src/locales/messages.es.xlf | 10 +++++----- apps/client/src/locales/messages.fr.xlf | 10 +++++----- apps/client/src/locales/messages.it.xlf | 10 +++++----- apps/client/src/locales/messages.nl.xlf | 10 +++++----- apps/client/src/locales/messages.pl.xlf | 10 +++++----- apps/client/src/locales/messages.pt.xlf | 10 +++++----- apps/client/src/locales/messages.tr.xlf | 10 +++++----- apps/client/src/locales/messages.uk.xlf | 10 +++++----- apps/client/src/locales/messages.xlf | 10 +++++----- apps/client/src/locales/messages.zh.xlf | 10 +++++----- 12 files changed, 60 insertions(+), 60 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index ec0121ab5..1e905750c 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -1723,7 +1723,7 @@ Realment vol eliminar el perfil d’aquest actiu? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -1731,7 +1731,7 @@ Realment vol eliminar aquests perfils? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -1739,7 +1739,7 @@ Oooh! No s’han pogut eliminar els perfils apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 @@ -6023,7 +6023,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6031,7 +6031,7 @@ Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 0bd543de9..c83497776 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -2566,7 +2566,7 @@ Möchtest du diese Aktivität wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -3942,7 +3942,7 @@ Möchtest du diese Aktivitäten wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6031,7 +6031,7 @@ Möchtest du dieses Anlageprofil wirklich löschen? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6715,7 +6715,7 @@ Möchtest du diese Profile wirklich löschen? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6723,7 +6723,7 @@ Ups! Die Profile konnten nicht gelöscht werden. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index da0c0fb5c..3b5896525 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -2567,7 +2567,7 @@ ¿Estás seguro de eliminar esta operación? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -3943,7 +3943,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6032,7 +6032,7 @@ Do you really want to delete this asset profile? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6716,7 +6716,7 @@ Estas seguro de borrar estos perfiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6724,7 +6724,7 @@ Oops! Could not delete profiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 77224f1c9..7a427083e 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -3086,7 +3086,7 @@ Voulez-vous vraiment supprimer cette activité ? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -3942,7 +3942,7 @@ Voulez-vous vraiment supprimer toutes vos activités ? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6031,7 +6031,7 @@ Confirmez la suppressoion de ce profil d'actif? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6715,7 +6715,7 @@ Confirmer la suppression de ces Profils? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6723,7 +6723,7 @@ Oops! Echec de la suppression de Profils. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 80ca9ced7..5813fb11b 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -2567,7 +2567,7 @@ Vuoi davvero eliminare questa attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -3943,7 +3943,7 @@ Vuoi davvero eliminare tutte le tue attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6032,7 +6032,7 @@ Vuoi veramente eliminare il profilo di questo asset? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6716,7 +6716,7 @@ Confermi di voler eliminare questi profili? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6724,7 +6724,7 @@ Ops! Impossibile eliminare i profili. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 8beeae481..77760e761 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -2566,7 +2566,7 @@ Wil je deze activiteit echt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -3942,7 +3942,7 @@ Wil je echt al je activiteiten verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6031,7 +6031,7 @@ Do you really want to delete this asset profile? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6715,7 +6715,7 @@ Do you really want to delete these profiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6723,7 +6723,7 @@ Oops! Could not delete profiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index d2001157e..015e72359 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -1455,7 +1455,7 @@ Czy na pewno chcesz usunąć ten profil aktywów? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -4207,7 +4207,7 @@ Czy na pewno chcesz usunąć te aktywności? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -5555,7 +5555,7 @@ Czy na pewno chcesz usunąć tę działalność? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -6715,7 +6715,7 @@ Czy na pewno chcesz usunąć te profile? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6723,7 +6723,7 @@ Ups! Nie udało się usunąć profili. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 10c72e589..515140679 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -2958,7 +2958,7 @@ Deseja realmente eliminar esta atividade? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -3942,7 +3942,7 @@ Deseja mesmo eliminar estas atividades? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6031,7 +6031,7 @@ Do you really want to delete this asset profile? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6715,7 +6715,7 @@ Do you really want to delete these profiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6723,7 +6723,7 @@ Oops! Could not delete profiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index ca2c9f99c..b5c2e6ae1 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -3715,7 +3715,7 @@ Tüm işlemlerinizi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -5271,7 +5271,7 @@ TBu işlemi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -6031,7 +6031,7 @@ Bu varlık profilini silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -6715,7 +6715,7 @@ Do you really want to delete these profiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6723,7 +6723,7 @@ Oops! Could not delete profiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index a6146f4b2..def058161 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -1635,7 +1635,7 @@ Ви дійсно хочете видалити цей профіль активу? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -1643,7 +1643,7 @@ Упс! Не вдалося видалити профілі. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 @@ -1651,7 +1651,7 @@ Ви дійсно хочете видалити ці профілі? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6669,7 +6669,7 @@ Ви дійсно хочете видалити ці дії? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -6677,7 +6677,7 @@ Ви дійсно хочете видалити цю активність? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index cb3bc15b3..18ac0c2be 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -1400,7 +1400,7 @@ Do you really want to delete this asset profile? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -3875,7 +3875,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -5112,7 +5112,7 @@ Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -6086,7 +6086,7 @@ Do you really want to delete these profiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6100,7 +6100,7 @@ Oops! Could not delete profiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 37db811ae..3f87d805b 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -1464,7 +1464,7 @@ 您确实要删除此资产配置文件吗? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 36 + 37 @@ -4216,7 +4216,7 @@ 您真的要删除所有活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 218 + 219 @@ -5596,7 +5596,7 @@ 您确实要删除此活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 228 + 229 @@ -6716,7 +6716,7 @@ Do you really want to delete these profiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 67 + 68 @@ -6724,7 +6724,7 @@ Oops! Could not delete profiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts - 55 + 56 From 25320e05d9f379194646e6a9fc42ad9fa8c856c9 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 6 Mar 2025 08:14:23 +0100 Subject: [PATCH 54/71] Release 2.144.0 (#4403) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 570112db2..432a953c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.144.0 - 2025-03-06 ### Fixed diff --git a/package-lock.json b/package-lock.json index 11e1b6ebd..cfda8ce42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.143.0", + "version": "2.144.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.143.0", + "version": "2.144.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 9df5e1172..4ca628470 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.143.0", + "version": "2.144.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From b260c4f450e126d656d8b81bdf3cc4377046e448 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:48:03 +0100 Subject: [PATCH 55/71] Feature/extend personal finance tools 20250306 (#4406) * Extend personal finance tools * CoinStats * Fincake * Koinly * Nansen * Simply Wall St * Tradervue --- libs/common/src/lib/personal-finance-tools.ts | 57 +++++++++++++++++++ libs/ui/src/lib/i18n.ts | 3 + 2 files changed, 60 insertions(+) diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index e4c820fb7..936f3c6f6 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -82,6 +82,16 @@ export const personalFinanceTools: Product[] = [ regions: ['Global'], slogan: 'Take control of your financial future' }, + { + founded: 2017, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'coinstats', + name: 'CoinStats', + origin: 'Armenia', + pricingPerYear: '$168', + slogan: 'Manage All Your Wallets & Exchanges From One Place' + }, { founded: 2013, hasFreePlan: true, @@ -154,6 +164,7 @@ export const personalFinanceTools: Product[] = [ name: 'Delta Investment Tracker', note: 'Acquired by eToro', origin: 'Belgium', + pricingPerYear: '$150', slogan: 'The app to track all your investments. Make smart moves only.' }, { @@ -252,6 +263,13 @@ export const personalFinanceTools: Product[] = [ slogan: 'The most convenient mobile application for personal finance accounting' }, + { + founded: 2022, + key: 'fincake', + name: 'Fincake', + origin: 'British Virgin Islands', + slogan: 'Easy-to-use Portfolio Tracker' + }, { founded: 2023, hasFreePlan: true, @@ -340,6 +358,15 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '€119', slogan: 'ETF portfolios made simple' }, + { + founded: 2018, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'koinly', + name: 'Koinly', + origin: 'Singapore', + slogan: 'Track all your crypto wallets in one place' + }, { founded: 2016, hasFreePlan: true, @@ -469,6 +496,16 @@ export const personalFinanceTools: Product[] = [ slogan: 'Track your equity, fund, investment trust, ETF and pension investments in one place.' }, + { + founded: 2020, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'nansen', + name: 'Crypto Portfolio Tracker by Nansen', + origin: 'Singapore', + pricingPerYear: '$1188', + slogan: 'Your Complete Crypto Portfolio, Reimagined' + }, { founded: 2017, hasFreePlan: false, @@ -634,6 +671,16 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '€80', slogan: 'Stock Portfolio Tracker' }, + { + founded: 2014, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'simply-wallstreet', + name: 'Stock Portfolio Tracker & Visualizer by Simply Wall St', + origin: 'Australia', + pricingPerYear: '$120', + slogan: 'Smart portfolio tracker for informed investors' + }, { founded: 2021, hasFreePlan: true, @@ -706,6 +753,16 @@ export const personalFinanceTools: Product[] = [ slogan: 'Your financial life in a spreadsheet, automatically updated each day' }, + { + founded: 2011, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'tradervue', + name: 'Tradervue', + origin: 'United States', + pricingPerYear: '$360', + slogan: 'The Trading Journal to Improve Your Trading Performance' + }, { hasFreePlan: true, hasSelfHostingAbility: false, diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts index 7ea36123b..4c09a4fc0 100644 --- a/libs/ui/src/lib/i18n.ts +++ b/libs/ui/src/lib/i18n.ts @@ -70,9 +70,11 @@ const locales = { 'South America': $localize`South America`, // Countries + Armenia: $localize`Armenia`, Australia: $localize`Australia`, Austria: $localize`Austria`, Belgium: $localize`Belgium`, + 'British Virgin Islands': $localize`British Virgin Islands`, Bulgaria: $localize`Bulgaria`, Canada: $localize`Canada`, 'Czech Republic': $localize`Czech Republic`, @@ -86,6 +88,7 @@ const locales = { 'New Zealand': $localize`New Zealand`, Poland: $localize`Poland`, Romania: $localize`Romania`, + Singapore: $localize`Singapore`, 'South Africa': $localize`South Africa`, Switzerland: $localize`Switzerland`, Thailand: $localize`Thailand`, From 589eefaa764090516f55a16d70899df7fe05ff4a Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:48:52 +0100 Subject: [PATCH 56/71] Feature/extend AI prompt API by mode (#4395) * Extend AI prompt API by mode * Update changelog --- CHANGELOG.md | 6 +++++ .../api/src/app/endpoints/ai/ai.controller.ts | 11 ++++++---- apps/api/src/app/endpoints/ai/ai.service.ts | 7 ++++++ .../analysis/analysis-page.component.ts | 6 ++--- .../portfolio/analysis/analysis-page.html | 22 +++++++++++++++++-- apps/client/src/app/services/data.service.ts | 11 +++++++--- .../src/lib/types/ai-prompt-mode.type.ts | 1 + libs/common/src/lib/types/index.ts | 2 ++ 8 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 libs/common/src/lib/types/ai-prompt-mode.type.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 432a953c0..88b90c943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added a _Copy portfolio data to clipboard for AI prompt_ action to the analysis page (experimental) + ## 2.144.0 - 2025-03-06 ### Fixed diff --git a/apps/api/src/app/endpoints/ai/ai.controller.ts b/apps/api/src/app/endpoints/ai/ai.controller.ts index 981b26aa2..910abbf96 100644 --- a/apps/api/src/app/endpoints/ai/ai.controller.ts +++ b/apps/api/src/app/endpoints/ai/ai.controller.ts @@ -6,9 +6,9 @@ import { } from '@ghostfolio/common/config'; import { AiPromptResponse } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; -import type { RequestWithUser } from '@ghostfolio/common/types'; +import type { AiPromptMode, RequestWithUser } from '@ghostfolio/common/types'; -import { Controller, Get, Inject, UseGuards } from '@nestjs/common'; +import { Controller, Get, Inject, Param, UseGuards } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; @@ -21,11 +21,14 @@ export class AiController { @Inject(REQUEST) private readonly request: RequestWithUser ) {} - @Get('prompt') + @Get('prompt/:mode') @HasPermission(permissions.readAiPrompt) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async getPrompt(): Promise { + public async getPrompt( + @Param('mode') mode: AiPromptMode + ): Promise { const prompt = await this.aiService.getPrompt({ + mode, impersonationId: undefined, languageCode: this.request.user.Settings.settings.language ?? DEFAULT_LANGUAGE_CODE, diff --git a/apps/api/src/app/endpoints/ai/ai.service.ts b/apps/api/src/app/endpoints/ai/ai.service.ts index 59dec6add..d9090d77c 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.ts +++ b/apps/api/src/app/endpoints/ai/ai.service.ts @@ -1,4 +1,5 @@ import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; +import type { AiPromptMode } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; @@ -9,11 +10,13 @@ export class AiService { public async getPrompt({ impersonationId, languageCode, + mode, userCurrency, userId }: { impersonationId: string; languageCode: string; + mode: AiPromptMode; userCurrency: string; userId: string; }) { @@ -43,6 +46,10 @@ export class AiService { ) ]; + if (mode === 'portfolio') { + return holdingsTable.join('\n'); + } + return [ `You are a neutral financial assistant. Please analyze the following investment portfolio (base currency being ${userCurrency}) in simple words.`, ...holdingsTable, diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 5eebb42ef..28c0b9c0e 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -12,7 +12,7 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { GroupBy } from '@ghostfolio/common/types'; +import type { AiPromptMode, GroupBy } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { Clipboard } from '@angular/cdk/clipboard'; @@ -142,9 +142,9 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { this.fetchDividendsAndInvestments(); } - public onCopyPromptToClipboard() { + public onCopyPromptToClipboard(mode: AiPromptMode) { this.dataService - .fetchPrompt() + .fetchPrompt(mode) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ prompt }) => { this.clipboard.copy(prompt); diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index 07ffa705d..84ca54e06 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -16,7 +16,7 @@ + diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 0bc4ebccc..e8d4b7826 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -46,7 +46,12 @@ import { User } from '@ghostfolio/common/interfaces'; import { filterGlobalPermissions } from '@ghostfolio/common/permissions'; -import { AccountWithValue, DateRange, GroupBy } from '@ghostfolio/common/types'; +import type { + AccountWithValue, + AiPromptMode, + DateRange, + GroupBy +} from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { HttpClient, HttpParams } from '@angular/common/http'; @@ -650,8 +655,8 @@ export class DataService { return this.http.get('/api/v1/portfolio/report'); } - public fetchPrompt() { - return this.http.get('/api/v1/ai/prompt'); + public fetchPrompt(mode: AiPromptMode) { + return this.http.get(`/api/v1/ai/prompt/${mode}`); } public fetchPublicPortfolio(aAccessId: string) { diff --git a/libs/common/src/lib/types/ai-prompt-mode.type.ts b/libs/common/src/lib/types/ai-prompt-mode.type.ts new file mode 100644 index 000000000..00a031df0 --- /dev/null +++ b/libs/common/src/lib/types/ai-prompt-mode.type.ts @@ -0,0 +1 @@ +export type AiPromptMode = 'analysis' | 'portfolio'; diff --git a/libs/common/src/lib/types/index.ts b/libs/common/src/lib/types/index.ts index 9e8178d3c..668486a94 100644 --- a/libs/common/src/lib/types/index.ts +++ b/libs/common/src/lib/types/index.ts @@ -2,6 +2,7 @@ import type { AccessType } from './access-type.type'; import type { AccessWithGranteeUser } from './access-with-grantee-user.type'; import type { AccountWithPlatform } from './account-with-platform.type'; import type { AccountWithValue } from './account-with-value.type'; +import type { AiPromptMode } from './ai-prompt-mode.type'; import type { BenchmarkTrend } from './benchmark-trend.type'; import type { ColorScheme } from './color-scheme.type'; import type { DateRange } from './date-range.type'; @@ -24,6 +25,7 @@ export type { AccessWithGranteeUser, AccountWithPlatform, AccountWithValue, + AiPromptMode, BenchmarkTrend, ColorScheme, DateRange, From 9278adc6ba3ab1b0d6978ec06de6294a156bfcda Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:12:55 +0100 Subject: [PATCH 57/71] Feature/update locales 20250307 (#4409) * Update translations * Update changelog --------- Co-authored-by: github-actions[bot] Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 4 + apps/client/src/locales/messages.ca.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.de.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.es.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.fr.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.it.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.nl.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.pl.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.pt.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.tr.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.uk.xlf | 126 +++++++++++++++--------- apps/client/src/locales/messages.xlf | 120 +++++++++++++--------- apps/client/src/locales/messages.zh.xlf | 126 +++++++++++++++--------- 13 files changed, 947 insertions(+), 563 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88b90c943..45af8de6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a _Copy portfolio data to clipboard for AI prompt_ action to the analysis page (experimental) +### Changed + +- Improved the language localization for German (`de`) + ## 2.144.0 - 2025-03-06 ### Fixed diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 1e905750c..3dc8d56f3 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -2671,7 +2671,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2683,7 +2683,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -5107,7 +5107,7 @@ Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -5115,7 +5115,7 @@ Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -5123,7 +5123,7 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -5131,7 +5131,7 @@ Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -5139,7 +5139,7 @@ Absolute Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -5147,7 +5147,7 @@ Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -5155,7 +5155,7 @@ Top apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -5163,7 +5163,7 @@ Bottom apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -5171,7 +5171,7 @@ Portfolio Evolution apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -5179,7 +5179,7 @@ Investment Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -5187,7 +5187,7 @@ Current Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -5195,7 +5195,7 @@ Longest Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -5203,7 +5203,7 @@ Dividend Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -5595,7 +5595,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6391,7 +6391,7 @@ Japan libs/ui/src/lib/i18n.ts - 84 + 86 @@ -6683,7 +6683,7 @@ Extreme Fear libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6691,7 +6691,7 @@ Extreme Greed libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6699,7 +6699,7 @@ Neutral libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6867,7 +6867,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Germany libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Poland libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ South Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index c83497776..962399d06 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -2134,7 +2134,7 @@ Zeitstrahl der Investitionen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -2142,7 +2142,7 @@ Gewinner apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -2150,7 +2150,7 @@ Verlierer apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -2850,7 +2850,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2862,7 +2862,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -2986,7 +2986,7 @@ Portfolio Wertentwicklung apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -3306,7 +3306,7 @@ Zeitstrahl der Dividenden apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4170,7 +4170,7 @@ Aktueller Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4178,7 +4178,7 @@ Längster Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4658,7 +4658,7 @@ Japan libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5759,7 +5759,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6111,7 +6111,7 @@ Extreme Angst libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6119,7 +6119,7 @@ Extreme Gier libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6127,7 +6127,7 @@ Neutral libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6315,7 +6315,7 @@ Absolute Anlage Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6323,7 +6323,7 @@ Anlage Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6331,7 +6331,7 @@ Absolute Währungsperformance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6339,7 +6339,7 @@ Währungsperformance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6347,7 +6347,7 @@ Absolute Netto Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6355,7 +6355,7 @@ Netto Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6867,7 +6867,7 @@ Australien libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Österreich libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgien libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bulgarien libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Kanada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ Tschechien libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finnland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ Frankreich libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Deutschland libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ Indien libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Italien libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Niederlande libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ Neuseeland libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Polen libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Rumänien libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ Südafrika libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ USA libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Kopiere KI-Anweisung die Zwischenablage - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link wurde in die Zwischenablage kopiert @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Kopiere Portfolio-Daten in die Zwischenablage für KI-Anweisung + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Kopiere KI-Anweisung in die Zwischenablage für Analyse + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenien + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + Britische Jungferninseln + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapur + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 3b5896525..0fca2e9e9 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -2135,7 +2135,7 @@ Cronología de la inversión apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -2143,7 +2143,7 @@ Lo mejor apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -2151,7 +2151,7 @@ Lo peor apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -2851,7 +2851,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2863,7 +2863,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -2987,7 +2987,7 @@ Evolución cartera apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -3319,7 +3319,7 @@ Calendario de dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4171,7 +4171,7 @@ Current Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4179,7 +4179,7 @@ Longest Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4659,7 +4659,7 @@ Japan libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5760,7 +5760,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6112,7 +6112,7 @@ Extreme Fear libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6120,7 +6120,7 @@ Extreme Greed libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6128,7 +6128,7 @@ Neutral libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6316,7 +6316,7 @@ Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6324,7 +6324,7 @@ Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6332,7 +6332,7 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6340,7 +6340,7 @@ Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6348,7 +6348,7 @@ Absolute Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6356,7 +6356,7 @@ Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6868,7 +6868,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6876,7 +6876,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6884,7 +6884,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6892,7 +6892,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6900,7 +6900,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6908,7 +6908,7 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6916,7 +6916,7 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6924,7 +6924,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6932,7 +6932,7 @@ Germany libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6940,7 +6940,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6948,7 +6948,7 @@ Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6956,7 +6956,7 @@ Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6964,7 +6964,7 @@ New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6972,7 +6972,7 @@ Poland libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6980,7 +6980,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6988,7 +6988,7 @@ South Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6996,7 +6996,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7004,7 +7004,7 @@ United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7348,7 +7348,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7625,14 +7625,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7765,6 +7757,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 7a427083e..244d0c494 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1378,7 +1378,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -1390,7 +1390,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -2774,7 +2774,7 @@ Haut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -2782,7 +2782,7 @@ Bas apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -2790,7 +2790,7 @@ Évolution du Portefeuille apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -2798,7 +2798,7 @@ Historique des Investissements apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -2806,7 +2806,7 @@ Historique des Dividendes apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4170,7 +4170,7 @@ Série en cours apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4178,7 +4178,7 @@ Série la plus longue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4658,7 +4658,7 @@ Japon libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5759,7 +5759,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6111,7 +6111,7 @@ Extreme Peur libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6119,7 +6119,7 @@ Extreme Cupidité libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6127,7 +6127,7 @@ Neutre libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6315,7 +6315,7 @@ Performance des Actifs en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6323,7 +6323,7 @@ Performance des Actifs apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6331,7 +6331,7 @@ Performance des devises en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6339,7 +6339,7 @@ Performance des devises apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6347,7 +6347,7 @@ Performance nette absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6355,7 +6355,7 @@ Performance nette apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6867,7 +6867,7 @@ Australie libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Autriche libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgique libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bulgarie libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ République Tchèque libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finlande libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Allemagne libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ Inde libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Italie libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Pays-Bas libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ Nouvelle-Zélande libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Pologne libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Roumanie libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ Afrique du Sud libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Thaïlande libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ Etats-Unis libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 5813fb11b..940c52abe 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -2135,7 +2135,7 @@ Cronologia degli investimenti apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -2143,7 +2143,7 @@ In alto apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -2151,7 +2151,7 @@ In basso apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -2851,7 +2851,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2863,7 +2863,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -2987,7 +2987,7 @@ Evoluzione del portafoglio apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -3319,7 +3319,7 @@ Cronologia dei dividendi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4171,7 +4171,7 @@ Serie attuale apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4179,7 +4179,7 @@ Serie più lunga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4659,7 +4659,7 @@ Giappone libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5760,7 +5760,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6112,7 +6112,7 @@ Paura estrema libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6120,7 +6120,7 @@ Avidità estrema libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6128,7 +6128,7 @@ Neutrale libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6316,7 +6316,7 @@ Rendimento assoluto dell'Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6324,7 +6324,7 @@ Rendimento dell'Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6332,7 +6332,7 @@ Rendimento assoluto della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6340,7 +6340,7 @@ Rendimento della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6348,7 +6348,7 @@ Rendimento assoluto della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6356,7 +6356,7 @@ Rendimento Netto apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6868,7 +6868,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6876,7 +6876,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6884,7 +6884,7 @@ Belgio libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6892,7 +6892,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6900,7 +6900,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6908,7 +6908,7 @@ Repubblica Ceca libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6916,7 +6916,7 @@ Finlandia libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6924,7 +6924,7 @@ Francia libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6932,7 +6932,7 @@ Germania libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6940,7 +6940,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6948,7 +6948,7 @@ Italia libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6956,7 +6956,7 @@ Olanda libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6964,7 +6964,7 @@ Nuova Zelanda libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6972,7 +6972,7 @@ Polonia libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6980,7 +6980,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6988,7 +6988,7 @@ Sud Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6996,7 +6996,7 @@ Tailandia libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7004,7 +7004,7 @@ Stati Uniti libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7348,7 +7348,7 @@ Ucraina libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7625,14 +7625,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7765,6 +7757,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 77760e761..d43fae4d6 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -2134,7 +2134,7 @@ Tijdlijn investeringen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -2142,7 +2142,7 @@ Winnaars apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -2150,7 +2150,7 @@ Verliezers apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -2850,7 +2850,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2862,7 +2862,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -2986,7 +2986,7 @@ Waardeontwikkeling van portefeuille apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -3318,7 +3318,7 @@ Tijdlijn dividend apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4170,7 +4170,7 @@ Huidige reeks apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4178,7 +4178,7 @@ Langste reeks apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4658,7 +4658,7 @@ Japan libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5759,7 +5759,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6111,7 +6111,7 @@ Extreme Fear libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6119,7 +6119,7 @@ Extreme Greed libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6127,7 +6127,7 @@ Neutral libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6315,7 +6315,7 @@ Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6323,7 +6323,7 @@ Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6331,7 +6331,7 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6339,7 +6339,7 @@ Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6347,7 +6347,7 @@ Absolute Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6355,7 +6355,7 @@ Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6867,7 +6867,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Germany libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Poland libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ South Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 015e72359..b6476dd9b 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -2327,7 +2327,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2339,7 +2339,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -4699,7 +4699,7 @@ Największe wzrosty apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -4707,7 +4707,7 @@ Największy spadek apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -4715,7 +4715,7 @@ Rozwój portfela apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -4723,7 +4723,7 @@ Oś czasu inwestycji apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -4731,7 +4731,7 @@ Obecna passa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4739,7 +4739,7 @@ Najdłuższa passa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4747,7 +4747,7 @@ Oś czasu dywidend apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -5383,7 +5383,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -5803,7 +5803,7 @@ Japonia libs/ui/src/lib/i18n.ts - 84 + 86 @@ -6087,7 +6087,7 @@ Skrajny Strach libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6095,7 +6095,7 @@ Skrajna Zachłanność libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6103,7 +6103,7 @@ Neutralny libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6315,7 +6315,7 @@ Łączny wynik aktywów apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6323,7 +6323,7 @@ Wyniki aktywów apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6331,7 +6331,7 @@ Łączny wynik walut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6339,7 +6339,7 @@ Wynik walut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6347,7 +6347,7 @@ Łączna wartość netto apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6355,7 +6355,7 @@ Wynik netto apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6867,7 +6867,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgia libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bułgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Kanada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ Czechy libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finlandia libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ Francja libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Niemcy libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ Indie libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Włochy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Holandia libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ Nowa Zelandia libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Polska libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Rumunia libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ Południowa Afryka libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Tajlandia libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ Stany Zjednoczone libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraina libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 515140679..6f2e546f8 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -1250,7 +1250,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -1262,7 +1262,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -2658,7 +2658,7 @@ Topo apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -2666,7 +2666,7 @@ Fundo apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -2674,7 +2674,7 @@ Evolução do Portefólio apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -2682,7 +2682,7 @@ Cronograma de Investimento apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -3386,7 +3386,7 @@ Cronograma de Dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4170,7 +4170,7 @@ Série Atual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4178,7 +4178,7 @@ Série mais Longa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4658,7 +4658,7 @@ Japão libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5759,7 +5759,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -6111,7 +6111,7 @@ Extreme Fear libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6119,7 +6119,7 @@ Extreme Greed libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6127,7 +6127,7 @@ Neutral libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6315,7 +6315,7 @@ Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6323,7 +6323,7 @@ Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6331,7 +6331,7 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6339,7 +6339,7 @@ Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6347,7 +6347,7 @@ Absolute Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6355,7 +6355,7 @@ Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6867,7 +6867,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Germany libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Poland libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ South Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index b5c2e6ae1..3b2927d10 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -2179,7 +2179,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2191,7 +2191,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -4183,7 +4183,7 @@ Üst apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -4191,7 +4191,7 @@ Alt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -4199,7 +4199,7 @@ Portföyün Gelişimi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -4207,7 +4207,7 @@ Yatırım Zaman Çizelgesi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -4215,7 +4215,7 @@ Güncel Seri apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4223,7 +4223,7 @@ En Uzun Seri apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4231,7 +4231,7 @@ Temettü Zaman Çizelgesi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4859,7 +4859,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -5483,7 +5483,7 @@ Japan libs/ui/src/lib/i18n.ts - 84 + 86 @@ -6111,7 +6111,7 @@ Aşırı Korku libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6119,7 +6119,7 @@ Aşırı Açgözlülük libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6127,7 +6127,7 @@ Nötr libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6315,7 +6315,7 @@ Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6323,7 +6323,7 @@ Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6331,7 +6331,7 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6339,7 +6339,7 @@ Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6347,7 +6347,7 @@ Absolute Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6355,7 +6355,7 @@ Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6867,7 +6867,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6875,7 +6875,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6883,7 +6883,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6891,7 +6891,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6899,7 +6899,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6907,7 +6907,7 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6915,7 +6915,7 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6923,7 +6923,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6931,7 +6931,7 @@ Germany libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6939,7 +6939,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6947,7 +6947,7 @@ Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6955,7 +6955,7 @@ Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6963,7 +6963,7 @@ New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6971,7 +6971,7 @@ Poland libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6979,7 +6979,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6987,7 +6987,7 @@ South Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6995,7 +6995,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7003,7 +7003,7 @@ United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7347,7 +7347,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7624,14 +7624,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index def058161..c192795af 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -2799,7 +2799,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2811,7 +2811,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -5383,7 +5383,7 @@ Абсолютна прибутковість активів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -5391,7 +5391,7 @@ Прибутковість активів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -5399,7 +5399,7 @@ Абсолютна прибутковість валюти apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -5407,7 +5407,7 @@ Прибутковість валюти apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -5415,7 +5415,7 @@ Абсолютна чиста прибутковість apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -5423,7 +5423,7 @@ Чиста прибутковість apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -5431,7 +5431,7 @@ Топ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -5439,7 +5439,7 @@ Низ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -5447,7 +5447,7 @@ Еволюція портфеля apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -5455,7 +5455,7 @@ Інвестиційний графік apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -5463,7 +5463,7 @@ Поточна серія apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -5471,7 +5471,7 @@ Найдовша серія apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -5479,7 +5479,7 @@ Графік дивідендів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -6009,7 +6009,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -7385,7 +7385,7 @@ Австралія libs/ui/src/lib/i18n.ts - 73 + 74 @@ -7393,7 +7393,7 @@ Австрія libs/ui/src/lib/i18n.ts - 74 + 75 @@ -7401,7 +7401,7 @@ Бельгія libs/ui/src/lib/i18n.ts - 75 + 76 @@ -7409,7 +7409,7 @@ Болгарія libs/ui/src/lib/i18n.ts - 76 + 78 @@ -7417,7 +7417,7 @@ Канада libs/ui/src/lib/i18n.ts - 77 + 79 @@ -7425,7 +7425,7 @@ Чеська Республіка libs/ui/src/lib/i18n.ts - 78 + 80 @@ -7433,7 +7433,7 @@ Фінляндія libs/ui/src/lib/i18n.ts - 79 + 81 @@ -7441,7 +7441,7 @@ Франція libs/ui/src/lib/i18n.ts - 80 + 82 @@ -7449,7 +7449,7 @@ Німеччина libs/ui/src/lib/i18n.ts - 81 + 83 @@ -7457,7 +7457,7 @@ Індія libs/ui/src/lib/i18n.ts - 82 + 84 @@ -7465,7 +7465,7 @@ Італія libs/ui/src/lib/i18n.ts - 83 + 85 @@ -7473,7 +7473,7 @@ Японія libs/ui/src/lib/i18n.ts - 84 + 86 @@ -7481,7 +7481,7 @@ Нідерланди libs/ui/src/lib/i18n.ts - 85 + 87 @@ -7489,7 +7489,7 @@ Нова Зеландія libs/ui/src/lib/i18n.ts - 86 + 88 @@ -7497,7 +7497,7 @@ Польща libs/ui/src/lib/i18n.ts - 87 + 89 @@ -7505,7 +7505,7 @@ Румунія libs/ui/src/lib/i18n.ts - 88 + 90 @@ -7513,7 +7513,7 @@ Південна Африка libs/ui/src/lib/i18n.ts - 89 + 92 @@ -7521,7 +7521,7 @@ Таїланд libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7529,7 +7529,7 @@ Україна libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7537,7 +7537,7 @@ Сполучені Штати libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7545,7 +7545,7 @@ Екстремальний страх libs/ui/src/lib/i18n.ts - 96 + 99 @@ -7553,7 +7553,7 @@ Екстремальна жадібність libs/ui/src/lib/i18n.ts - 97 + 100 @@ -7561,7 +7561,7 @@ Нейтрально libs/ui/src/lib/i18n.ts - 100 + 103 @@ -7632,14 +7632,6 @@ 153 - - Copy AI prompt to clipboard - Скопіюйте запит AI в буфер обміну - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Early Access Ранній доступ @@ -7764,6 +7756,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 18ac0c2be..7dc410df5 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -2188,7 +2188,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2199,7 +2199,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -4315,49 +4315,49 @@ Top apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 Bottom apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 Portfolio Evolution apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 Investment Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 Current Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 Longest Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 Dividend Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -4951,7 +4951,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -5345,7 +5345,7 @@ Japan libs/ui/src/lib/i18n.ts - 84 + 86 @@ -5594,21 +5594,21 @@ Extreme Fear libs/ui/src/lib/i18n.ts - 96 + 99 Extreme Greed libs/ui/src/lib/i18n.ts - 97 + 100 Neutral libs/ui/src/lib/i18n.ts - 100 + 103 @@ -5733,21 +5733,21 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 Absolute Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -5769,21 +5769,21 @@ Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 Net Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6149,35 +6149,35 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 India libs/ui/src/lib/i18n.ts - 82 + 84 Austria libs/ui/src/lib/i18n.ts - 74 + 75 Poland libs/ui/src/lib/i18n.ts - 87 + 89 Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6219,21 +6219,21 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6268,21 +6268,21 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 Germany libs/ui/src/lib/i18n.ts - 81 + 83 United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -6296,7 +6296,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6310,28 +6310,28 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 Australia libs/ui/src/lib/i18n.ts - 73 + 74 South Africa libs/ui/src/lib/i18n.ts - 89 + 92 Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6345,14 +6345,14 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6632,7 +6632,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -6891,13 +6891,6 @@ 57 - - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - AI prompt has been copied to the clipboard @@ -7021,6 +7014,41 @@ 378 + + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + + + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 3f87d805b..15f8c9d83 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -2336,7 +2336,7 @@ libs/ui/src/lib/i18n.ts - 98 + 101 @@ -2348,7 +2348,7 @@ libs/ui/src/lib/i18n.ts - 99 + 102 @@ -4708,7 +4708,7 @@ 顶部 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 197 + 215 @@ -4716,7 +4716,7 @@ 底部 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 246 + 264 @@ -4724,7 +4724,7 @@ 投资组合演变 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 299 + 317 @@ -4732,7 +4732,7 @@ 投资时间表 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 326 + 344 @@ -4740,7 +4740,7 @@ 当前连胜 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 347 + 365 @@ -4748,7 +4748,7 @@ 最长连续纪录 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 356 + 374 @@ -4756,7 +4756,7 @@ 股息时间表 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 383 + 401 @@ -5416,7 +5416,7 @@ libs/ui/src/lib/i18n.ts - 90 + 93 @@ -5860,7 +5860,7 @@ 日本 libs/ui/src/lib/i18n.ts - 84 + 86 @@ -6144,7 +6144,7 @@ 极度恐惧 libs/ui/src/lib/i18n.ts - 96 + 99 @@ -6152,7 +6152,7 @@ 极度贪婪 libs/ui/src/lib/i18n.ts - 97 + 100 @@ -6160,7 +6160,7 @@ 中性的 libs/ui/src/lib/i18n.ts - 100 + 103 @@ -6300,7 +6300,7 @@ 绝对货币表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 103 + 121 @@ -6308,7 +6308,7 @@ 绝对净性能 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 150 + 168 @@ -6316,7 +6316,7 @@ 绝对资产绩效 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 60 + 78 @@ -6340,7 +6340,7 @@ 资产绩效 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 81 + 99 @@ -6348,7 +6348,7 @@ 净绩效 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 169 + 187 @@ -6356,7 +6356,7 @@ 货币表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 127 + 145 @@ -6868,7 +6868,7 @@ Australia libs/ui/src/lib/i18n.ts - 73 + 74 @@ -6876,7 +6876,7 @@ Austria libs/ui/src/lib/i18n.ts - 74 + 75 @@ -6884,7 +6884,7 @@ Belgium libs/ui/src/lib/i18n.ts - 75 + 76 @@ -6892,7 +6892,7 @@ Bulgaria libs/ui/src/lib/i18n.ts - 76 + 78 @@ -6900,7 +6900,7 @@ Canada libs/ui/src/lib/i18n.ts - 77 + 79 @@ -6908,7 +6908,7 @@ Czech Republic libs/ui/src/lib/i18n.ts - 78 + 80 @@ -6916,7 +6916,7 @@ Finland libs/ui/src/lib/i18n.ts - 79 + 81 @@ -6924,7 +6924,7 @@ France libs/ui/src/lib/i18n.ts - 80 + 82 @@ -6932,7 +6932,7 @@ Germany libs/ui/src/lib/i18n.ts - 81 + 83 @@ -6940,7 +6940,7 @@ India libs/ui/src/lib/i18n.ts - 82 + 84 @@ -6948,7 +6948,7 @@ Italy libs/ui/src/lib/i18n.ts - 83 + 85 @@ -6956,7 +6956,7 @@ Netherlands libs/ui/src/lib/i18n.ts - 85 + 87 @@ -6964,7 +6964,7 @@ New Zealand libs/ui/src/lib/i18n.ts - 86 + 88 @@ -6972,7 +6972,7 @@ Poland libs/ui/src/lib/i18n.ts - 87 + 89 @@ -6980,7 +6980,7 @@ Romania libs/ui/src/lib/i18n.ts - 88 + 90 @@ -6988,7 +6988,7 @@ South Africa libs/ui/src/lib/i18n.ts - 89 + 92 @@ -6996,7 +6996,7 @@ Thailand libs/ui/src/lib/i18n.ts - 91 + 94 @@ -7004,7 +7004,7 @@ United States libs/ui/src/lib/i18n.ts - 93 + 96 @@ -7348,7 +7348,7 @@ Ukraine libs/ui/src/lib/i18n.ts - 92 + 95 @@ -7625,14 +7625,6 @@ 153 - - Copy AI prompt to clipboard - Copy AI prompt to clipboard - - apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 27 - - Link has been copied to the clipboard Link has been copied to the clipboard @@ -7765,6 +7757,46 @@ 378 + + Copy portfolio data to clipboard for AI prompt + Copy portfolio data to clipboard for AI prompt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 28 + + + + Copy AI prompt to clipboard for analysis + Copy AI prompt to clipboard for analysis + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 44 + + + + Armenia + Armenia + + libs/ui/src/lib/i18n.ts + 73 + + + + British Virgin Islands + British Virgin Islands + + libs/ui/src/lib/i18n.ts + 77 + + + + Singapore + Singapore + + libs/ui/src/lib/i18n.ts + 91 + + From ff73e7e0ee364701501d0198e995ff2b9f3e46b8 Mon Sep 17 00:00:00 2001 From: Tobias Kugel <78074722+tobikugel@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:34:29 -0300 Subject: [PATCH 58/71] Feature/adapt style of X-ray rule to summary (#4394) * Adapt style of X-ray rule to summary * Update changelog --- CHANGELOG.md | 1 + .../app/components/rule/rule.component.scss | 2 +- .../portfolio/x-ray/x-ray-page.component.html | 63 ++++++++++++++----- .../portfolio/x-ray/x-ray-page.component.scss | 14 +++++ 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45af8de6b..5c9bda697 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the style of the summary on the _X-ray_ page - Improved the language localization for German (`de`) ## 2.144.0 - 2025-03-06 diff --git a/apps/client/src/app/components/rule/rule.component.scss b/apps/client/src/app/components/rule/rule.component.scss index 54ddce823..adb081abc 100644 --- a/apps/client/src/app/components/rule/rule.component.scss +++ b/apps/client/src/app/components/rule/rule.component.scss @@ -2,7 +2,7 @@ display: block; .icon-container { - background-color: rgba(var(--dark-primary-text), 0.05); + background-color: rgba(var(--palette-foreground-base), 0.02); border-radius: 0.25rem; height: 2rem; diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html index 6ec5722b7..24ca0f474 100644 --- a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html @@ -7,23 +7,58 @@ risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy.

    -

    +

    @if (isLoading) { - +
    + + +
    } @else { - {{ statistics?.rulesFulfilledCount }} - out of - {{ statistics?.rulesActiveCount }} - rules align with your portfolio. +
    + @if ( + statistics?.rulesActiveCount === 0 || + statistics?.rulesFulfilledCount === 0 + ) { + + } @else if ( + statistics?.rulesFulfilledCount === statistics?.rulesActiveCount + ) { + + } @else { + + } +
    +
    + {{ statistics?.rulesFulfilledCount }} + out of + {{ statistics?.rulesActiveCount }} + rules align with your portfolio. +
    } -

    +
    Date: Sat, 8 Mar 2025 08:36:27 +0100 Subject: [PATCH 59/71] Update locales (#4411) Co-authored-by: github-actions[bot] --- apps/client/src/locales/messages.ca.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.de.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.es.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.fr.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.it.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.nl.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.pl.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.pt.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.tr.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.uk.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.xlf | 20 ++++++++++---------- apps/client/src/locales/messages.zh.xlf | 20 ++++++++++---------- 12 files changed, 120 insertions(+), 120 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 3dc8d56f3..24df1cef4 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -2603,7 +2603,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -2975,7 +2975,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -5243,7 +5243,7 @@ Currency Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5251,7 +5251,7 @@ Account Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 962399d06..5f3f0b8e5 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -1242,7 +1242,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -3758,7 +3758,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5903,7 +5903,7 @@ Währungsklumpenrisiken apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5911,7 +5911,7 @@ Kontoklumpenrisiken apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Inaktiv apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Wirtschaftsraumklumpenrisiken apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ von apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ Regeln werden von Ihrem Portfolio erfüllt. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Anlageklasseklumpenrisiken apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regionale Marktklumpenrisiken apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 0fca2e9e9..15254d8f2 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -1243,7 +1243,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -3759,7 +3759,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5904,7 +5904,7 @@ Currency Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5912,7 +5912,7 @@ Account Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7036,7 +7036,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7438,7 +7438,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7566,7 +7566,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7574,7 +7574,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7590,7 +7590,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7646,7 +7646,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 244d0c494..e249579de 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1586,7 +1586,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -3758,7 +3758,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5903,7 +5903,7 @@ Risques de change apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5911,7 +5911,7 @@ Risques liés aux regroupements de comptes apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Inactif apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 940c52abe..bf05d1e07 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -1243,7 +1243,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -3759,7 +3759,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5904,7 +5904,7 @@ Rischio di Concentrazione Valutario apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5912,7 +5912,7 @@ Rischi di Concentrazione dei Conti apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7036,7 +7036,7 @@ Inattivo apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7438,7 +7438,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7566,7 +7566,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7574,7 +7574,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7590,7 +7590,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7646,7 +7646,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index d43fae4d6..d6678c99a 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -1242,7 +1242,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -3758,7 +3758,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5903,7 +5903,7 @@ Currency Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5911,7 +5911,7 @@ Account Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index b6476dd9b..485c86d7c 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -2587,7 +2587,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -2635,7 +2635,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -4779,7 +4779,7 @@ Ryzyko związane z klastrem walutowym apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -4787,7 +4787,7 @@ Ryzyko związane z klastrem kont apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Nieaktywny apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Ryzyko związane z klastrem rynków gospodarczych apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ poza apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ zasady zgodne z Twoim portfelem. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Ryzyko klastra klasy aktywów apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 6f2e546f8..4c4a763fb 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -1466,7 +1466,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -3758,7 +3758,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5903,7 +5903,7 @@ Currency Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5911,7 +5911,7 @@ Account Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 3b2927d10..c84ddb5f1 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -2471,7 +2471,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -2627,7 +2627,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -5903,7 +5903,7 @@ Kur Kümelenme Riskleri (Currency Cluster Risks) apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5911,7 +5911,7 @@ Hesap Kümelenme Riski (Account Cluster Risks) apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7035,7 +7035,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7437,7 +7437,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7565,7 +7565,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7573,7 +7573,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7589,7 +7589,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index c192795af..0ac3b347b 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -2731,7 +2731,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -3071,7 +3071,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -5527,7 +5527,7 @@ з apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -5535,7 +5535,7 @@ правила узгоджуються з вашим портфелем. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -5543,7 +5543,7 @@ Ризики зосередження валюти apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -5551,7 +5551,7 @@ Ризики зосередження класу активів apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -5559,7 +5559,7 @@ Ризики зосередження рахунків apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -5567,7 +5567,7 @@ Ризики зосередження економічного ринку apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -5575,7 +5575,7 @@ Неактивний apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7645,7 +7645,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 7dc410df5..4241f4601 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -2422,7 +2422,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -2465,7 +2465,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -4385,14 +4385,14 @@ Currency Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 Account Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -6380,7 +6380,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -6727,7 +6727,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -6846,14 +6846,14 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -6867,7 +6867,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -6916,7 +6916,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 15f8c9d83..3d07023d9 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -2596,7 +2596,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 178 + 213 @@ -2644,7 +2644,7 @@ apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 34 + 69 @@ -4788,7 +4788,7 @@ 货币集群风险 apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 58 + 93 @@ -4796,7 +4796,7 @@ 账户集群风险 apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 106 + 141 @@ -7036,7 +7036,7 @@ Inactive apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 197 + 232 @@ -7438,7 +7438,7 @@ Economic Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 130 + 165 @@ -7566,7 +7566,7 @@ out of apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 22 + 56 @@ -7574,7 +7574,7 @@ rules align with your portfolio. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 24 + 58 @@ -7590,7 +7590,7 @@ Asset Class Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 82 + 117 @@ -7646,7 +7646,7 @@ Regional Market Cluster Risks apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html - 154 + 189 From bdde9dd314c96c6460030aaba43a3452aa3b616d Mon Sep 17 00:00:00 2001 From: Ken Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sun, 9 Mar 2025 03:33:47 +0700 Subject: [PATCH 60/71] Task/upgrade to simplewebauthn version 13.1 (#4407) * Upgrade to simplewebauthn version 13.1 * Update changelog --- CHANGELOG.md | 4 ++ apps/api/src/app/auth/web-auth.service.ts | 33 ++++++++------ .../src/app/services/web-authn.service.ts | 6 +-- package-lock.json | 43 +++++-------------- package.json | 5 +-- 5 files changed, 39 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c9bda697..c7006932f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 2.144.0 - 2025-03-06 +### Changed + +- Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `9.0` to `13.1` + ### Fixed - Fixed the missing import functionality on the non-empty activities page diff --git a/apps/api/src/app/auth/web-auth.service.ts b/apps/api/src/app/auth/web-auth.service.ts index 2f8dd1018..5678ef7fe 100644 --- a/apps/api/src/app/auth/web-auth.service.ts +++ b/apps/api/src/app/auth/web-auth.service.ts @@ -24,6 +24,7 @@ import { verifyRegistrationResponse, VerifyRegistrationResponseOpts } from '@simplewebauthn/server'; +import { isoBase64URL, isoUint8Array } from '@simplewebauthn/server/helpers'; import { AssertionCredentialJSON, @@ -54,10 +55,9 @@ export class WebAuthService { const opts: GenerateRegistrationOptionsOpts = { rpName: 'Ghostfolio', rpID: this.rpID, - userID: user.id, + userID: isoUint8Array.fromUTF8String(user.id), userName: '', timeout: 60000, - attestationType: 'indirect', authenticatorSelection: { authenticatorAttachment: 'platform', requireResidentKey: false, @@ -111,11 +111,17 @@ export class WebAuthService { where: { userId: user.id } }); if (registrationInfo && verified) { - const { counter, credentialID, credentialPublicKey } = registrationInfo; + const { + credential: { + counter, + id: credentialId, + publicKey: credentialPublicKey + } + } = registrationInfo; - let existingDevice = devices.find( - (device) => device.credentialId === credentialID - ); + let existingDevice = devices.find((device) => { + return isoBase64URL.fromBuffer(device.credentialId) === credentialId; + }); if (!existingDevice) { /** @@ -123,7 +129,7 @@ export class WebAuthService { */ existingDevice = await this.deviceService.createAuthDevice({ counter, - credentialId: Buffer.from(credentialID), + credentialId: Buffer.from(credentialId), credentialPublicKey: Buffer.from(credentialPublicKey), User: { connect: { id: user.id } } }); @@ -148,9 +154,8 @@ export class WebAuthService { const opts: GenerateAuthenticationOptionsOpts = { allowCredentials: [ { - id: device.credentialId, - transports: ['internal'], - type: 'public-key' + id: isoBase64URL.fromBuffer(device.credentialId), + transports: ['internal'] } ], rpID: this.rpID, @@ -187,10 +192,10 @@ export class WebAuthService { let verification: VerifiedAuthenticationResponse; try { const opts: VerifyAuthenticationResponseOpts = { - authenticator: { - credentialID: device.credentialId, - credentialPublicKey: device.credentialPublicKey, - counter: device.counter + credential: { + counter: device.counter, + id: isoBase64URL.fromBuffer(device.credentialId), + publicKey: device.credentialPublicKey }, expectedChallenge: `${user.authChallenge}`, expectedOrigin: this.expectedOrigin, diff --git a/apps/client/src/app/services/web-authn.service.ts b/apps/client/src/app/services/web-authn.service.ts index c5e186362..76352cb7b 100644 --- a/apps/client/src/app/services/web-authn.service.ts +++ b/apps/client/src/app/services/web-authn.service.ts @@ -45,7 +45,7 @@ export class WebAuthnService { return of(null); }), switchMap((attOps) => { - return startRegistration(attOps); + return startRegistration({ optionsJSON: attOps }); }), switchMap((credential) => { return this.http.post( @@ -89,8 +89,8 @@ export class WebAuthnService { { deviceId } ) .pipe( - switchMap((requestOptionsJSON) => { - return startAuthentication(requestOptionsJSON); + switchMap((optionsJSON) => { + return startAuthentication({ optionsJSON }); }), switchMap((credential) => { return this.http.post<{ authToken: string }>( diff --git a/package-lock.json b/package-lock.json index cfda8ce42..b03084f50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,8 +41,8 @@ "@nestjs/schedule": "4.1.2", "@nestjs/serve-static": "4.0.2", "@prisma/client": "6.4.1", - "@simplewebauthn/browser": "9.0.1", - "@simplewebauthn/server": "9.0.3", + "@simplewebauthn/browser": "13.1.0", + "@simplewebauthn/server": "13.1.1", "@stripe/stripe-js": "5.4.0", "alphavantage": "2.2.0", "big.js": "6.2.2", @@ -120,7 +120,6 @@ "@nx/web": "20.3.2", "@nx/workspace": "20.3.2", "@schematics/angular": "19.0.6", - "@simplewebauthn/types": "9.0.1", "@storybook/addon-essentials": "8.4.7", "@storybook/addon-interactions": "8.4.7", "@storybook/angular": "8.4.7", @@ -9225,18 +9224,15 @@ } }, "node_modules/@simplewebauthn/browser": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-9.0.1.tgz", - "integrity": "sha512-wD2WpbkaEP4170s13/HUxPcAV5y4ZXaKo1TfNklS5zDefPinIgXOpgz1kpEvobAsaLPa2KeH7AKKX/od1mrBJw==", - "license": "MIT", - "dependencies": { - "@simplewebauthn/types": "^9.0.1" - } + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.1.0.tgz", + "integrity": "sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==", + "license": "MIT" }, "node_modules/@simplewebauthn/server": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-9.0.3.tgz", - "integrity": "sha512-FMZieoBosrVLFxCnxPFD9Enhd1U7D8nidVDT4MsHc6l4fdVcjoeHjDueeXCloO1k5O/fZg1fsSXXPKbY2XTzDA==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.1.1.tgz", + "integrity": "sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==", "license": "MIT", "dependencies": { "@hexagon/base64": "^1.1.27", @@ -9245,29 +9241,12 @@ "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "@simplewebauthn/types": "^9.0.1", - "cross-fetch": "^4.0.0" + "@peculiar/asn1-x509": "^2.3.8" }, "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@simplewebauthn/server/node_modules/cross-fetch": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" + "node": ">=20.0.0" } }, - "node_modules/@simplewebauthn/types": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@simplewebauthn/types/-/types-9.0.1.tgz", - "integrity": "sha512-tGSRP1QvsAvsJmnOlRQyw/mvK9gnPtjEc5fg2+m8n+QUa+D7rvrKkOYyfpy42GTs90X3RDOnqJgfHt+qO67/+w==", - "license": "MIT" - }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", diff --git a/package.json b/package.json index 4ca628470..ce4ce4f2a 100644 --- a/package.json +++ b/package.json @@ -87,8 +87,8 @@ "@nestjs/schedule": "4.1.2", "@nestjs/serve-static": "4.0.2", "@prisma/client": "6.4.1", - "@simplewebauthn/browser": "9.0.1", - "@simplewebauthn/server": "9.0.3", + "@simplewebauthn/browser": "13.1.0", + "@simplewebauthn/server": "13.1.1", "@stripe/stripe-js": "5.4.0", "alphavantage": "2.2.0", "big.js": "6.2.2", @@ -166,7 +166,6 @@ "@nx/web": "20.3.2", "@nx/workspace": "20.3.2", "@schematics/angular": "19.0.6", - "@simplewebauthn/types": "9.0.1", "@storybook/addon-essentials": "8.4.7", "@storybook/addon-interactions": "8.4.7", "@storybook/angular": "8.4.7", From d346f6b9fabd7cf1e2cbbf106f6517067520ef49 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:36:13 +0100 Subject: [PATCH 61/71] Bugfix/fix changelog (#4412) * Update changelog --- CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7006932f..6b5c01483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,13 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the style of the summary on the _X-ray_ page - Improved the language localization for German (`de`) +- Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `9.0` to `13.1` ## 2.144.0 - 2025-03-06 -### Changed - -- Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `9.0` to `13.1` - ### Fixed - Fixed the missing import functionality on the non-empty activities page From 25d0c1c8a04df9275a7e341a2a00b58b287271c5 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 9 Mar 2025 10:22:32 +0100 Subject: [PATCH 62/71] Bugfix/fix symbols in API page (#4408) * Fix symbols --- apps/client/src/app/pages/api/api-page.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/client/src/app/pages/api/api-page.component.ts b/apps/client/src/app/pages/api/api-page.component.ts index 039bf8691..350650060 100644 --- a/apps/client/src/app/pages/api/api-page.component.ts +++ b/apps/client/src/app/pages/api/api-page.component.ts @@ -40,8 +40,8 @@ export class GfApiPageComponent implements OnInit { this.apiKey = prompt($localize`Please enter your Ghostfolio API key:`); this.dividends$ = this.fetchDividends({ symbol: 'KO' }); - this.historicalData$ = this.fetchHistoricalData({ symbol: 'AAPL.US' }); - this.quotes$ = this.fetchQuotes({ symbols: ['AAPL.US', 'VOO.US'] }); + this.historicalData$ = this.fetchHistoricalData({ symbol: 'AAPL' }); + this.quotes$ = this.fetchQuotes({ symbols: ['AAPL', 'VOO.US'] }); this.status$ = this.fetchStatus(); this.symbols$ = this.fetchSymbols({ query: 'apple' }); } From cb1f488eb46728d3462726e7f43ca0c18ac3c7f8 Mon Sep 17 00:00:00 2001 From: csehatt741 <77381875+csehatt741@users.noreply.github.com> Date: Sun, 9 Mar 2025 10:56:39 +0100 Subject: [PATCH 63/71] Feature/extend export by account balances (#4390) * Extend export by account balances * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/account/account.service.ts | 20 ++++++++++++++++--- apps/api/src/app/export/export.service.ts | 5 +++++ .../src/lib/interfaces/export.interface.ts | 4 +++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b5c01483..05daaabf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Extended the export functionality by the account balances - Added a _Copy portfolio data to clipboard for AI prompt_ action to the analysis page (experimental) ### Changed diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index df369859b..aab4c0766 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -7,7 +7,13 @@ import { Filter } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { Account, Order, Platform, Prisma } from '@prisma/client'; +import { + Account, + AccountBalance, + Order, + Platform, + Prisma +} from '@prisma/client'; import { Big } from 'big.js'; import { format } from 'date-fns'; import { groupBy } from 'lodash'; @@ -56,13 +62,19 @@ export class AccountService { orderBy?: Prisma.AccountOrderByWithRelationInput; }): Promise< (Account & { + balances?: AccountBalance[]; Order?: Order[]; Platform?: Platform; })[] > { const { include = {}, skip, take, cursor, where, orderBy } = params; - include.balances = { orderBy: { date: 'desc' }, take: 1 }; + const isBalancesIncluded = !!include.balances; + + include.balances = { + orderBy: { date: 'desc' }, + ...(isBalancesIncluded ? {} : { take: 1 }) + }; const accounts = await this.prismaService.account.findMany({ cursor, @@ -76,7 +88,9 @@ export class AccountService { return accounts.map((account) => { account = { ...account, balance: account.balances[0]?.value ?? 0 }; - delete account.balances; + if (!isBalancesIncluded) { + delete account.balances; + } return account; }); diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index c6c24d6af..8b9d2c56c 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -31,6 +31,7 @@ export class ExportService { const accounts = ( await this.accountService.accounts({ include: { + balances: true, Platform: true }, orderBy: { @@ -41,6 +42,7 @@ export class ExportService { ).map( ({ balance, + balances, comment, currency, id, @@ -55,6 +57,9 @@ export class ExportService { return { balance, + balances: balances.map(({ date, value }) => { + return { date: date.toISOString(), value }; + }), comment, currency, id, diff --git a/libs/common/src/lib/interfaces/export.interface.ts b/libs/common/src/lib/interfaces/export.interface.ts index 14a017428..0772159e6 100644 --- a/libs/common/src/lib/interfaces/export.interface.ts +++ b/libs/common/src/lib/interfaces/export.interface.ts @@ -1,7 +1,9 @@ import { Account, Order, Platform, Tag } from '@prisma/client'; export interface Export { - accounts: Omit[]; + accounts: (Omit & { + balances: { date: string; value: number }[]; + })[]; activities: (Omit< Order, | 'accountUserId' From 52081d6741cafc8fb87ffa83d062ed1d577978a8 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 9 Mar 2025 12:07:23 +0100 Subject: [PATCH 64/71] Bugfix/exclude Storybook from html template middleware (#4414) * Exclude storybook * Update changelog --- CHANGELOG.md | 4 ++++ apps/api/src/middlewares/html-template.middleware.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05daaabf2..f153f2831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for German (`de`) - Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `9.0` to `13.1` +### Fixed + +- Fixed an issue with serving _Storybook_ + ## 2.144.0 - 2025-03-06 ### Fixed diff --git a/apps/api/src/middlewares/html-template.middleware.ts b/apps/api/src/middlewares/html-template.middleware.ts index 6c929c388..b6c8f2e54 100644 --- a/apps/api/src/middlewares/html-template.middleware.ts +++ b/apps/api/src/middlewares/html-template.middleware.ts @@ -129,6 +129,7 @@ export const HtmlTemplateMiddleware = async ( if ( path.startsWith('/api/') || + path.startsWith('/development/storybook') || isFileRequest(path) || !environment.production ) { From 6bdfd8984ff9614a1d452a14bc39b27a669defe1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 9 Mar 2025 12:28:33 +0100 Subject: [PATCH 65/71] Bugfix/fix fetching dividend and historical market data in Financial Modeling Prep service (#4416) * Add default values * Update changelog --- CHANGELOG.md | 2 ++ .../financial-modeling-prep.service.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f153f2831..579536ef7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed an issue to get dividends in the _Financial Modeling Prep_ service +- Fixed an issue to get historical market data in the _Financial Modeling Prep_ service - Fixed an issue with serving _Storybook_ ## 2.144.0 - 2025-03-06 diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index 2d42fe21c..6a3d0d41f 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -244,7 +244,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { [date: string]: IDataProviderHistoricalResponse; } = {}; - const { historical } = await fetch( + const { historical = [] } = await fetch( `${this.URL}/historical-price-full/stock_dividend/${symbol}?apikey=${this.apiKey}`, { signal: AbortSignal.timeout(requestTimeout) @@ -305,7 +305,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { ? addYears(currentFrom, MAX_YEARS_PER_REQUEST) : to; - const { historical } = await fetch( + const { historical = [] } = await fetch( `${this.URL}/historical-price-full/${symbol}?apikey=${this.apiKey}&from=${format(currentFrom, DATE_FORMAT)}&to=${format(currentTo, DATE_FORMAT)}`, { signal: AbortSignal.timeout(requestTimeout) From 7ca07202447e3f86c4315599dfc60bdd18d78fae Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 9 Mar 2025 12:31:11 +0100 Subject: [PATCH 66/71] Release 2.145.0 (#4417) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 579536ef7..bc5eba78f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.145.0 - 2025-03-09 ### Added diff --git a/package-lock.json b/package-lock.json index b03084f50..3d147aafd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.144.0", + "version": "2.145.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.144.0", + "version": "2.145.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index ce4ce4f2a..430621aed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.144.0", + "version": "2.145.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From feea2ced8279fa851e0a7af7ea62ac5f7e169c11 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 10 Mar 2025 17:40:38 +0100 Subject: [PATCH 67/71] Feature/update certificate for development (#4418) * Update certificate for development * Extend documentation --- DEVELOPMENT.md | 9 +++++++ apps/client/localhost.cert | 34 +++++++++++++------------ apps/client/localhost.pem | 52 +++++++++++++++++++------------------- 3 files changed, 53 insertions(+), 42 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 9e32b56eb..cea43095d 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -101,3 +101,12 @@ https://www.prisma.io/docs/concepts/components/prisma-migrate/db-push Run `npm run prisma migrate dev --name added_job_title` https://www.prisma.io/docs/concepts/components/prisma-migrate#getting-started-with-prisma-migrate + +## SSL + +Generate `localhost.cert` and `localhost.pem` files. + +``` +openssl req -x509 -newkey rsa:2048 -nodes -keyout apps/client/localhost.pem -out apps/client/localhost.cert -days 365 \ + -subj "/C=CH/ST=State/L=City/O=Organization/OU=Unit/CN=localhost" +``` diff --git a/apps/client/localhost.cert b/apps/client/localhost.cert index 12f31dd27..882ddd2a4 100644 --- a/apps/client/localhost.cert +++ b/apps/client/localhost.cert @@ -1,18 +1,20 @@ -----BEGIN CERTIFICATE----- -MIIC5TCCAc2gAwIBAgIJAJAMHOFnJ6oyMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV -BAMMCWxvY2FsaG9zdDAeFw0yNDAyMjcxNTQ2MzFaFw0yNDAzMjgxNTQ2MzFaMBQx -EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAJ0hRjViikEKVIyukXR4CfuYVvFEFzB6AwAQ9Jrz2MseqpLacLTXFFAS54mp -iDuqPBzs9ta40mlSrqSBuAWKikpW5kTNnmqUnDZ6iSJezbYWx9YyULGqqb1q3C4/ -5pH9m6NHJ+2uaUNKlDxYNKbntqs3drQEdxH9yv672Z53nvogTcf9jz6zjutEQGSV -HgVkCTTQmzf3+3st+VJ5D8JeYFR+tpZ6yleqgXFaTMtPZRfKLvTkQ+KeyCJLnsUJ -BQvdCKI0PGsG6d6ygXFmSePolD9KW3VTKKDPCsndID89vAnRWDj9UhzvycxmKpcF -GrUPH5+Pis1PM1R7OnAvnFygnyECAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo -b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B -AQsFAAOCAQEAOdzrY3RTAPnBVAd3/GKIEkielYyOgKPnvd+RcOB+je8cXZY+vaxX -uEFP0526G00+kRZ2Tx9t0SmjoSpwg3lHUPMko0dIxgRlqISDAohdrEptHpcVujsD -ak88LLnAurr60JNjWX2wbEoJ18KLtqGSnATdmCgKwDPIN5a7+ssp44BGyzH6VYCg -wV3VjJl0pp4C5M0Jfu0p1FrQjzIVhgqR7JFYmvqIogWrGwYAQK/3XRXq8t48J5X3 -IsfWiLAA2ZdCoWAnZ6PAGBOoGivtkJm967pHjd/28qYY6mQo4sN2ksEOjx6/YslF -2mOJdLV/DzqoggUsTpPEG0dRhzQLTGHKDQ== +MIIDSDCCAjACCQCQ2ForVhz+uDANBgkqhkiG9w0BAQsFADBmMQswCQYDVQQGEwJD +SDEOMAwGA1UECAwFU3RhdGUxDTALBgNVBAcMBENpdHkxFTATBgNVBAoMDE9yZ2Fu +aXphdGlvbjENMAsGA1UECwwEVW5pdDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1 +MDMwOTE2MzQxM1oXDTI2MDMwOTE2MzQxM1owZjELMAkGA1UEBhMCQ0gxDjAMBgNV +BAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYDVQQKDAxPcmdhbml6YXRpb24x +DTALBgNVBAsMBFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMkJRKPgV8NDcoIakPc7sZVXQ9VK2PGb8+lF/1Lv +NcIZpD40+p4DzuEw0bjRn17IDClyLMaLbZNtIyTPSkFaffL+rJ0JvnKdG50s+HId +YNuCwKkgHg4hTXFzOPpT3HMG3UxyEwFOm25GMFiikfT96ukMAAkanMqYKZQOClRU +Cw4LP3g0Oks58obbRy4Wltp88K8LJrR+j81+AjElTIGXHhChXzV/NjJ14TMNy5hZ +lwV4xUSwvNqOvWGMIR7J77fINF130ghTSnvzCS52dCeom2I4Lvncz3m37lDttCOs +Wm/i651ro7pwFEs/lJmrnFHPtph2ayPcHBmrQCgLc5xMUMcCAwEAATANBgkqhkiG +9w0BAQsFAAOCAQEAhRA1/+Gl2VH34yN/FvrE5cY0W4ghSCuTdK9pGeo8AcN+TScU +7O+hVsEwZDrYKuDvG8Ab//A+uv5gbfGbYPJVIdJ3Q8HKijNZmbwAgANJU/c0WwOx +XBQ9mCzWRcJxQeUUgh4DT4lZCOfR5pIvAJpKScTcF/yp5gOgrgJH1GHFEYYPoXWO +ezPPMwCNbfamUPlZZnHu74fUrFrDPI9c/YSu8Ex/LegZXJAEzA+8I0g64rjGtzJp +fkRDyQcBuT5SVa+USBlALQmdIuT/fN6R729DcGzvV8JqdoG9sLra4hrRCn3+A3c9 +izZguW1BQNQ2N7II6QCDnWkdUFSQCiQunX/xsg== -----END CERTIFICATE----- diff --git a/apps/client/localhost.pem b/apps/client/localhost.pem index dc2a7ff5a..05a480779 100644 --- a/apps/client/localhost.pem +++ b/apps/client/localhost.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCdIUY1YopBClSM -rpF0eAn7mFbxRBcwegMAEPSa89jLHqqS2nC01xRQEueJqYg7qjwc7PbWuNJpUq6k -gbgFiopKVuZEzZ5qlJw2eokiXs22FsfWMlCxqqm9atwuP+aR/ZujRyftrmlDSpQ8 -WDSm57arN3a0BHcR/cr+u9med576IE3H/Y8+s47rREBklR4FZAk00Js39/t7LflS -eQ/CXmBUfraWespXqoFxWkzLT2UXyi705EPinsgiS57FCQUL3QiiNDxrBunesoFx -Zknj6JQ/Slt1UyigzwrJ3SA/PbwJ0Vg4/VIc78nMZiqXBRq1Dx+fj4rNTzNUezpw -L5xcoJ8hAgMBAAECggEAPU5YOEgELTA8oM8TjV+wdWuQsH2ilpVkSkhTR4nQkh+a -6cU0qDoqgLt/fySYNL9MyPRjso9V+SX7YdAC3paZMjwJh9q57lehQ1g33SMkG+Fz -gs0K0ucFZxQkaB8idN+ANAp1N7UO+ORGRe0cTeqmSNNRCxea5XgiFZVxaPS/IFOR -vVdXS1DulgwHh4H0ljKmkj7jc9zPBSc9ccW5Ml2q4a26Atu4IC/Mlp/DF4GNELbD -ebi9ZOZG33ip2bdhj3WX7NW9GJaaViKtVUpcpR6u+6BfvTXQ6xrqdoxXk9fnPzzf -sSoLPTt8yO4RavP1zQU22PhgIcWudhCiy/2Nv+uLqQKBgQDMPh1/xwdFl8yES8dy -f0xJyCDWPiB+xzGwcOAC90FrNZaqG0WWs3VHE4cilaWjCflvdR6aAEDEY68sZJhl -h+ChT/g61QLMOI+VIDQ1kJXKYgfS/B+BE1PZ0EkuymKFOvbNO8agHodB8CqnZaQh -bLuZaDnZ0JLK4im3KPt70+aKYwKBgQDE8s6xl0SLu+yJLo3VklCRD67Z8/jlvx2t -h3DF6NG8pB3QmvKdJWFKuLAWLGflJwbUW9Pt3hXkc0649KQrtiIYC0ZMh9KMaVCk -WmjS/n2eIUQZ7ZUlwFesi4p4iGynVBavIY8TJ6Y+K3TvsJgXP3IZ96r689PQJo8E -KbSeyYzFqwKBgGQTS4EAlJ+U8bEhMGj51veQCAbyChoUoFRD+n95h6RwbZKMKlzd -MenRt7VKfg6VJJNoX8Y1uYaBEaQ+5i1Zlsdz1718AhLu4+u+C9bzMXIo9ox63TTx -s3RWioVSxVNiwOtvDrQGQWAdvcioFPQLwyA34aDIgiTHDImimxbhjWThAoGAWOqW -Tq9QjxWk0Lpn5ohMP3GpK1VuhasnJvUDARb/uf8ORuPtrOz3Y9jGBvy9W0OnXbCn -mbiugZldbTtl8yYjdl+AuYSIlkPl2I3IzZl/9Shnqp0MvSJ9crT9KzXMeC8Knr6z -7Z30/BR6ksxTngtS5E5grzPt6Qe/gc2ich3kpEkCgYBfBHUhVIKVrDW/8a7U2679 -Wj4i9us/M3iPMxcTv7/ZAg08TEvNBQYtvVQLu0NfDKXx8iGKJJ6evIYgNXVm2sPq -VzSgwGCALi1X0443amZU+mnX+/9RnBqyM+PJU8570mM83jqKlY/BEsi0aqxTioFG -an3xbjjN+Rq9iKLzmPxIMg== +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJCUSj4FfDQ3KC +GpD3O7GVV0PVStjxm/PpRf9S7zXCGaQ+NPqeA87hMNG40Z9eyAwpcizGi22TbSMk +z0pBWn3y/qydCb5ynRudLPhyHWDbgsCpIB4OIU1xczj6U9xzBt1MchMBTptuRjBY +opH0/erpDAAJGpzKmCmUDgpUVAsOCz94NDpLOfKG20cuFpbafPCvCya0fo/NfgIx +JUyBlx4QoV81fzYydeEzDcuYWZcFeMVEsLzajr1hjCEeye+3yDRdd9IIU0p78wku +dnQnqJtiOC753M95t+5Q7bQjrFpv4uuda6O6cBRLP5SZq5xRz7aYdmsj3BwZq0Ao +C3OcTFDHAgMBAAECggEBALJQqDN7QB0QbDb+fWrt5bwDJUXBF+BmZdiZn7jeOJ6r +w8TxlQIneo6/kKYQOP4HDtKMVS7eaRkFCtERlFmXfHPWdSDtjaF3vRCS3OPLLyhF +N8JLnJ0H6PsiKn3PeJAGnK+71yOnp7IOS7+yoyfdOUnwvO9WTZBdmzOZqIvX595R +g7R5yjSYjzFMmaCpyab6kiD7b4bHzDIrB0XuouT2W/fS/i1srwc3eDk78ZyioyiB +g6GDuOwqDfPmkUqKo2oXSoSR8yCwSSdlClc7aOowoNxbsksTDjXf1k02n0lG5MHU +ldCX02WdA0JFW8Os0Ig+YBq7wSkB5oNVt7gEek/MB0ECgYEA+ATkyfX9/5X2kUMY +MatUqKOvLUtyIfHeYUy/Dm+9JlZlrxD0dRAKWhnhRR16v5cwN2RVtEvMDsV1AGHN +e/fh315aAq+I6/eY6syXfkeHHs5UIRPrOlIcp1Ogfg99xpOT0/TZy9bB7lKvtYes +GmKO8n7md1TptdxilSNORI60KvECgYEAz4FX6vH76HgV/seY+vePrj5nFCZnDru7 +16w5LYoHaX0hABJ0qZCqZozdPf9mqM5Ldc8PUbvVsFqXyaHwBAKUsH44a3aLxcXU +JMsQanU5I87SWP/S8Xu2Yxc10L66Oc5VdAeraZvb+wJqTkYKhDYOJVMjyuI/vkAw +fqMPI6wShzcCgYEAndYnb6uf4Eakap9jR0C8mLHKaq3nzVhqaEt6DwrnOf2jqnzE +xbbWj66GoQB4vHLP2YB91kaibwgURJD5PxpqYUdfSvRA08J3S322L0P/5ofyHDbb +7PqSh539thvPtE74tdvNux5Jvoxai9Dyorv0Mri1nF2qefTtu/GC/rg+SlECgYB2 +FaYhhomTVls1/QIat6zlPI/OULhPExineFOljaoAJvwTnW0UXcYKy9jPgjs6jwM0 +TJvsKFdHn5ZHYUdEEO/qrDmRNgn+h0Ddm02BN6pHrVfY2+SAFaXKKBgw7YjugnPw +rrimRdLeuhYi6wrrCBPuu6xftXcO3lp6hnKEG1UD6wKBgEh/C7HQ6cjb7Rr15eRq +2VOgeuz7o2v/OC+jO6yFGRrs2VKoBuJpw/6jx806Cbi2jLEwim21iNYW/2McOWP3 +YUvni7qHXfll8d4sSAuCTA4K/N0MJ/3XbGBPDm/83J2o7uz2GFkQRruruaERvDMF +x26H2i3DOUFzdgbkoNB0ifHd -----END PRIVATE KEY----- From 70cd1a89b513bb58441d1b9f9c23a25cdf0b4816 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:45:41 +0100 Subject: [PATCH 68/71] Feature/extend Ghostfolio data provider (#4420) * Extend Ghostfolio data provider --- .../ghostfolio/ghostfolio.controller.ts | 36 ++++++++++ .../ghostfolio/ghostfolio.service.ts | 43 +++++++++++- .../alpha-vantage/alpha-vantage.service.ts | 5 +- .../coingecko/coingecko.service.ts | 5 +- .../eod-historical-data.service.ts | 5 +- .../financial-modeling-prep.service.ts | 38 ++++------- .../ghostfolio/ghostfolio.service.ts | 68 +++++++++++++------ .../google-sheets/google-sheets.service.ts | 5 +- .../interfaces/data-provider.interface.ts | 10 ++- .../data-provider/manual/manual.service.ts | 5 +- .../rapid-api/rapid-api.service.ts | 5 +- .../yahoo-finance/yahoo-finance.service.ts | 5 +- libs/common/src/lib/interfaces/index.ts | 2 + ...tfolio-asset-profile-response.interface.ts | 4 ++ 14 files changed, 165 insertions(+), 71 deletions(-) create mode 100644 libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-asset-profile-response.interface.ts diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts index f3386f8a7..83c7317f0 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts @@ -2,6 +2,7 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { parseDate } from '@ghostfolio/common/helper'; import { + DataProviderGhostfolioAssetProfileResponse, DataProviderGhostfolioStatusResponse, DividendsResponse, HistoricalResponse, @@ -37,6 +38,41 @@ export class GhostfolioController { @Inject(REQUEST) private readonly request: RequestWithUser ) {} + @Get('asset-profile/:symbol') + @HasPermission(permissions.enableDataProviderGhostfolio) + @UseGuards(AuthGuard('api-key'), HasPermissionGuard) + public async getAssetProfile( + @Param('symbol') symbol: string + ): Promise { + const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); + + if ( + this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + + try { + const assetProfile = await this.ghostfolioService.getAssetProfile({ + symbol + }); + + await this.ghostfolioService.incrementDailyRequests({ + userId: this.request.user.id + }); + + return assetProfile; + } catch { + throw new HttpException( + getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR), + StatusCodes.INTERNAL_SERVER_ERROR + ); + } + } + /** * @deprecated */ diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts index 78685a61b..7281697bd 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -15,6 +16,7 @@ import { } from '@ghostfolio/common/config'; import { PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS } from '@ghostfolio/common/config'; import { + DataProviderGhostfolioAssetProfileResponse, DataProviderInfo, DividendsResponse, HistoricalResponse, @@ -25,7 +27,7 @@ import { import { UserWithSettings } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; -import { DataSource } from '@prisma/client'; +import { DataSource, SymbolProfile } from '@prisma/client'; import { Big } from 'big.js'; @Injectable() @@ -37,6 +39,44 @@ export class GhostfolioService { private readonly propertyService: PropertyService ) {} + public async getAssetProfile({ + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbol + }: GetAssetProfileParams) { + let result: DataProviderGhostfolioAssetProfileResponse = {}; + + try { + const promises: Promise>[] = []; + + for (const dataProviderService of this.getDataProviderServices()) { + promises.push( + dataProviderService + .getAssetProfile({ + requestTimeout, + symbol + }) + .then((assetProfile) => { + result = { + ...result, + ...assetProfile, + dataSource: DataSource.GHOSTFOLIO + }; + + return assetProfile; + }) + ); + } + + await Promise.all(promises); + + return result; + } catch (error) { + Logger.error(error, 'GhostfolioService'); + + throw error; + } + } + public async getDividends({ from, granularity, @@ -277,6 +317,7 @@ export class GhostfolioService { }); results.items = filteredItems; + return results; } catch (error) { Logger.error(error, 'GhostfolioService'); diff --git a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts index 5c9eee127..606e6b7fd 100644 --- a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts +++ b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -41,9 +42,7 @@ export class AlphaVantageService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { return { symbol, dataSource: this.getName() diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts index fb1fa9b63..d53355b9c 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -56,9 +57,7 @@ export class CoinGeckoService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { const response: Partial = { symbol, assetClass: AssetClass.LIQUIDITY, diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index e427a830a..376b8f159 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -51,9 +52,7 @@ export class EodHistoricalDataService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { const [searchResult] = await this.getSearchResult(symbol); return { diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index 6a3d0d41f..5216ed214 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -2,6 +2,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -56,10 +57,9 @@ export class FinancialModelingPrepService implements DataProviderInterface { } public async getAssetProfile({ + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { const response: Partial = { symbol, dataSource: this.getName() @@ -70,9 +70,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const [quote] = await fetch( `${this.URL}/quote/${symbol}?apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -84,9 +82,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const [assetProfile] = await fetch( `${this.URL}/profile/${symbol}?apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -100,9 +96,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const etfCountryWeightings = await fetch( `${this.URL}/etf-country-weightings/${symbol}?apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -127,9 +121,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const [etfInformation] = await fetch( `${this.getUrl({ version: 4 })}/etf-info?symbol=${symbol}&apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -140,9 +132,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const [portfolioDate] = await fetch( `${this.getUrl({ version: 4 })}/etf-holdings/portfolio-date?symbol=${symbol}&apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -150,9 +140,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const etfHoldings = await fetch( `${this.getUrl({ version: 4 })}/etf-holdings?date=${portfolioDate.date}&symbol=${symbol}&apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -170,9 +158,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { const etfSectorWeightings = await fetch( `${this.URL}/etf-sector-weightings/${symbol}?apikey=${this.apiKey}`, { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json()); @@ -211,7 +197,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { if (error?.name === 'AbortError') { message = `RequestError: The operation to get the asset profile for ${symbol} was aborted because the request to the data provider took more than ${( - this.configurationService.get('REQUEST_TIMEOUT') / 1000 + requestTimeout / 1000 ).toFixed(3)} seconds`; } @@ -376,7 +362,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { if (error?.name === 'AbortError') { message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( - this.configurationService.get('REQUEST_TIMEOUT') / 1000 + requestTimeout / 1000 ).toFixed(3)} seconds`; } diff --git a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts index a674d479a..097464e2f 100644 --- a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts +++ b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts @@ -2,6 +2,7 @@ import { environment } from '@ghostfolio/api/environments/environment'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -18,6 +19,7 @@ import { } from '@ghostfolio/common/config'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { + DataProviderGhostfolioAssetProfileResponse, DataProviderInfo, DividendsResponse, HistoricalResponse, @@ -46,21 +48,46 @@ export class GhostfolioService implements DataProviderInterface { } public async getAssetProfile({ + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), symbol - }: { - symbol: string; - }): Promise> { - const { items } = await this.search({ query: symbol }); - const searchResult = items?.[0]; + }: GetAssetProfileParams): Promise> { + let response: DataProviderGhostfolioAssetProfileResponse = {}; - return { - symbol, - assetClass: searchResult?.assetClass, - assetSubClass: searchResult?.assetSubClass, - currency: searchResult?.currency, - dataSource: this.getName(), - name: searchResult?.name - }; + try { + const assetProfile = (await fetch( + `${this.URL}/v1/data-providers/ghostfolio/asset-profile/${symbol}`, + { + headers: await this.getRequestHeaders(), + signal: AbortSignal.timeout(requestTimeout) + } + ).then((res) => + res.json() + )) as DataProviderGhostfolioAssetProfileResponse; + + response = assetProfile; + } catch (error) { + let message = error; + + if (error.name === 'AbortError') { + message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( + requestTimeout / 1000 + ).toFixed(3)} seconds`; + } else if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { + message = 'RequestError: The daily request limit has been exceeded'; + } else if (error.response?.statusCode === StatusCodes.UNAUTHORIZED) { + if (!error.request?.options?.headers?.authorization?.includes('-')) { + message = + 'RequestError: The provided API key is invalid. Please update it in the Settings section of the Admin Control panel.'; + } else { + message = + 'RequestError: The provided API key has expired. Please request a new one and update it in the Settings section of the Admin Control panel.'; + } + } + + Logger.error(message, 'GhostfolioService'); + } + + return response; } public getDataProviderInfo(): DataProviderInfo { @@ -203,7 +230,7 @@ export class GhostfolioService implements DataProviderInterface { if (error.name === 'AbortError') { message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( - this.configurationService.get('REQUEST_TIMEOUT') / 1000 + requestTimeout / 1000 ).toFixed(3)} seconds`; } else if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { message = 'RequestError: The daily request limit has been exceeded'; @@ -224,10 +251,13 @@ export class GhostfolioService implements DataProviderInterface { } public getTestSymbol() { - return 'AAPL.US'; + return 'AAPL'; } - public async search({ query }: GetSearchParams): Promise { + public async search({ + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + query + }: GetSearchParams): Promise { let searchResult: LookupResponse = { items: [] }; try { @@ -235,9 +265,7 @@ export class GhostfolioService implements DataProviderInterface { `${this.URL}/v2/data-providers/ghostfolio/lookup?query=${query}`, { headers: await this.getRequestHeaders(), - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + signal: AbortSignal.timeout(requestTimeout) } ).then((res) => res.json())) as LookupResponse; } catch (error) { @@ -245,7 +273,7 @@ export class GhostfolioService implements DataProviderInterface { if (error.name === 'AbortError') { message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( - this.configurationService.get('REQUEST_TIMEOUT') / 1000 + requestTimeout / 1000 ).toFixed(3)} seconds`; } else if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { message = 'RequestError: The daily request limit has been exceeded'; diff --git a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts index f18d670d1..0c466972d 100644 --- a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts +++ b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -37,9 +38,7 @@ export class GoogleSheetsService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { return { symbol, dataSource: this.getName() diff --git a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts index 5c316aac2..475205a01 100644 --- a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts +++ b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts @@ -15,9 +15,7 @@ export interface DataProviderInterface { getAssetProfile({ symbol - }: { - symbol: string; - }): Promise>; + }: GetAssetProfileParams): Promise>; getDataProviderInfo(): DataProviderInfo; @@ -55,6 +53,11 @@ export interface DataProviderInterface { search({ includeIndices, query }: GetSearchParams): Promise; } +export interface GetAssetProfileParams { + requestTimeout?: number; + symbol: string; +} + export interface GetDividendsParams { from: Date; granularity?: Granularity; @@ -79,5 +82,6 @@ export interface GetQuotesParams { export interface GetSearchParams { includeIndices?: boolean; query: string; + requestTimeout?: number; userId?: string; } diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index dfda922c6..331806098 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -43,9 +44,7 @@ export class ManualService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { const assetProfile: Partial = { symbol, dataSource: this.getName() diff --git a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts index 4c9bb2717..7762be426 100644 --- a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts @@ -1,6 +1,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -33,9 +34,7 @@ export class RapidApiService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { return { symbol, dataSource: this.getName() diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index 27da18ab0..72ae1ff97 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -2,6 +2,7 @@ import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/c import { YahooFinanceDataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service'; import { DataProviderInterface, + GetAssetProfileParams, GetDividendsParams, GetHistoricalParams, GetQuotesParams, @@ -43,9 +44,7 @@ export class YahooFinanceService implements DataProviderInterface { public async getAssetProfile({ symbol - }: { - symbol: string; - }): Promise> { + }: GetAssetProfileParams): Promise> { return this.yahooFinanceDataEnhancerService.getAssetProfile(symbol); } diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index 7ad4948dc..3dcbbb32a 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -41,6 +41,7 @@ import type { AccountBalancesResponse } from './responses/account-balances-respo import type { AiPromptResponse } from './responses/ai-prompt-response.interface'; import type { ApiKeyResponse } from './responses/api-key-response.interface'; import type { BenchmarkResponse } from './responses/benchmark-response.interface'; +import type { DataProviderGhostfolioAssetProfileResponse } from './responses/data-provider-ghostfolio-asset-profile-response.interface'; import type { DataProviderGhostfolioStatusResponse } from './responses/data-provider-ghostfolio-status-response.interface'; import type { DividendsResponse } from './responses/dividends-response.interface'; import type { ResponseError } from './responses/errors.interface'; @@ -83,6 +84,7 @@ export { BenchmarkProperty, BenchmarkResponse, Coupon, + DataProviderGhostfolioAssetProfileResponse, DataProviderGhostfolioStatusResponse, DataProviderInfo, DividendsResponse, diff --git a/libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-asset-profile-response.interface.ts b/libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-asset-profile-response.interface.ts new file mode 100644 index 000000000..7fd0314fb --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-asset-profile-response.interface.ts @@ -0,0 +1,4 @@ +import { SymbolProfile } from '@prisma/client'; + +export interface DataProviderGhostfolioAssetProfileResponse + extends Partial {} From 9abc4af203f2113062586a14cd0a4c5483d37618 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:47:27 +0100 Subject: [PATCH 69/71] Release 2.145.1 (#4422) --- CHANGELOG.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5eba78f..2257cf608 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.145.0 - 2025-03-09 +## 2.145.1 - 2025-03-10 ### Added diff --git a/package-lock.json b/package-lock.json index 3d147aafd..5fbff830c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.145.0", + "version": "2.145.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.145.0", + "version": "2.145.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 430621aed..56d6d6d2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.145.0", + "version": "2.145.1", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From a137bbbdcaed087687407b63addc4baaa832308b Mon Sep 17 00:00:00 2001 From: Tobias Kugel <78074722+tobikugel@users.noreply.github.com> Date: Wed, 12 Mar 2025 09:42:25 -0300 Subject: [PATCH 70/71] Feature/restructure user account registration flow (#4393) * Restructure user account registration flow * Update changelog --- CHANGELOG.md | 6 + .../pages/register/register-page.component.ts | 25 +--- .../src/app/pages/register/register-page.html | 2 +- .../show-access-token-dialog.component.ts | 57 ++++++-- .../show-access-token-dialog.html | 125 ++++++++++++------ .../show-access-token-dialog.module.ts | 4 + .../show-access-token-dialog.scss | 4 + 7 files changed, 151 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2257cf608..be7daaff4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Improved the usability of the user account registration + ## 2.145.1 - 2025-03-10 ### Added diff --git a/apps/client/src/app/pages/register/register-page.component.ts b/apps/client/src/app/pages/register/register-page.component.ts index 86490688b..45fd53fcc 100644 --- a/apps/client/src/app/pages/register/register-page.component.ts +++ b/apps/client/src/app/pages/register/register-page.component.ts @@ -7,7 +7,6 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; -import { Role } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -59,15 +58,6 @@ export class RegisterPageComponent implements OnDestroy, OnInit { ); } - public async createAccount() { - this.dataService - .postUser() - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ accessToken, authToken, role }) => { - this.openShowAccessTokenDialog(accessToken, authToken, role); - }); - } - public async onLoginWithInternetIdentity() { try { const { authToken } = await this.internetIdentityService.login(); @@ -76,17 +66,8 @@ export class RegisterPageComponent implements OnDestroy, OnInit { } catch {} } - public openShowAccessTokenDialog( - accessToken: string, - authToken: string, - role: Role - ) { + public openShowAccessTokenDialog() { const dialogRef = this.dialog.open(ShowAccessTokenDialog, { - data: { - accessToken, - authToken, - role - }, disableClose: true, width: '30rem' }); @@ -94,8 +75,8 @@ export class RegisterPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((data) => { - if (data?.authToken) { + .subscribe((authToken) => { + if (authToken) { this.tokenStorageService.saveToken(authToken, true); this.router.navigate(['/']); diff --git a/apps/client/src/app/pages/register/register-page.html b/apps/client/src/app/pages/register/register-page.html index 903aedccf..eee49083a 100644 --- a/apps/client/src/app/pages/register/register-page.html +++ b/apps/client/src/app/pages/register/register-page.html @@ -22,7 +22,7 @@ class="d-inline-block" color="primary" mat-flat-button - (click)="createAccount()" + (click)="openShowAccessTokenDialog()" > Create Account diff --git a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.component.ts b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.component.ts index 5aacbd457..c6535bf48 100644 --- a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.component.ts +++ b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.component.ts @@ -1,19 +1,58 @@ -import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { DataService } from '@ghostfolio/client/services/data.service'; + +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ViewChild +} from '@angular/core'; +import { MatStepper } from '@angular/material/stepper'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; @Component({ - selector: 'gf-show-access-token-dialog', changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'gf-show-access-token-dialog', + standalone: false, styleUrls: ['./show-access-token-dialog.scss'], - templateUrl: 'show-access-token-dialog.html', - standalone: false + templateUrl: 'show-access-token-dialog.html' }) export class ShowAccessTokenDialog { - public isAgreeButtonDisabled = true; + @ViewChild(MatStepper) stepper!: MatStepper; + + public accessToken: string; + public authToken: string; + public isCreateAccountButtonDisabled = true; + public isDisclaimerChecked = false; + public role: string; + + private unsubscribeSubject = new Subject(); + + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private dataService: DataService + ) {} - public constructor(@Inject(MAT_DIALOG_DATA) public data: any) {} + public createAccount() { + this.dataService + .postUser() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ accessToken, authToken, role }) => { + this.accessToken = accessToken; + this.authToken = authToken; + this.role = role; + + this.stepper.next(); + + this.changeDetectorRef.markForCheck(); + }); + } + + public enableCreateAccountButton() { + this.isCreateAccountButtonDisabled = false; + } - public enableAgreeButton() { - this.isAgreeButtonDisabled = false; + public onChangeDislaimerChecked() { + this.isDisclaimerChecked = !this.isDisclaimerChecked; } } diff --git a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html index 0a6a2e5e3..737d32679 100644 --- a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html +++ b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html @@ -1,48 +1,93 @@

    Create Account - @if (data.role === 'ADMIN') { - {{ data.role }} + @if (role === 'ADMIN') { + {{ role }} }

    -
    -
    - - Security Token - -
    - +
    +
    + + Continue + +
    - -
    -

    - I agree to have stored my Security Token from above in a secure - place. If I lose it, I cannot get my account back. -

    -
    -
    - - + + + Security Token +
    + Here is your security token. It is only visible once, please store + and keep it in a safe place. +
    + + Security Token + +
    + +
    +
    +
    +
    + +
    +
    +
    + + + + + +
    diff --git a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.module.ts b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.module.ts index d537fbe7f..117c1da00 100644 --- a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.module.ts +++ b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.module.ts @@ -4,9 +4,11 @@ import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; +import { MatStepperModule } from '@angular/material/stepper'; import { ShowAccessTokenDialog } from './show-access-token-dialog.component'; @@ -17,9 +19,11 @@ import { ShowAccessTokenDialog } from './show-access-token-dialog.component'; CommonModule, FormsModule, MatButtonModule, + MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatInputModule, + MatStepperModule, ReactiveFormsModule, TextFieldModule ], diff --git a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.scss b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.scss index dc9093b45..777c8c854 100644 --- a/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.scss +++ b/apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.scss @@ -1,2 +1,6 @@ :host { + .mat-mdc-dialog-actions { + padding-left: 0 !important; + padding-right: 0 !important; + } } From 0f6fe700375f9808d10b1dd4782b474a4bd37756 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 12 Mar 2025 16:03:07 +0100 Subject: [PATCH 71/71] Fix TagService location --- .../asset-profile-dialog/asset-profile-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index f43b4596a..62841840c 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -142,7 +142,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit { } public initialize() { - this.adminService + this.dataService .fetchTags() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((tags) => {