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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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/48] 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