From 73c127f10cb12a690b27261be1aa86936ffca758 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 20 May 2023 10:10:53 +0200 Subject: [PATCH 01/18] Bugfix/fix vertical alignment in gf toggle (#1991) * Fix alignment * Update changelog --- CHANGELOG.md | 6 ++++++ apps/client/src/app/components/toggle/toggle.component.html | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c953ec05..dd6113437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Fixed the vertical alignment in the toggle component + ## 1.270.1 - 2023-05-19 ### Added diff --git a/apps/client/src/app/components/toggle/toggle.component.html b/apps/client/src/app/components/toggle/toggle.component.html index 582aa433e..fd923fdf5 100644 --- a/apps/client/src/app/components/toggle/toggle.component.html +++ b/apps/client/src/app/components/toggle/toggle.component.html @@ -1,10 +1,11 @@ Date: Sat, 20 May 2023 10:53:04 +0200 Subject: [PATCH 02/18] Feature/improve local number formatting in value component (#1992) * Improve local number formatting * Update changelog --- CHANGELOG.md | 4 +++ apps/api/src/app/info/info.service.ts | 8 ++++-- .../app/subscription/subscription.service.ts | 2 +- .../app/pages/about/about-page.component.ts | 3 +- .../src/app/pages/about/about-page.html | 28 ++++++++++++++++--- .../pages/landing/landing-page.component.ts | 2 +- .../src/app/pages/open/open-page.component.ts | 26 +++++++++++++---- apps/client/src/app/pages/open/open-page.html | 22 ++++++++++++--- libs/common/src/lib/interfaces/index.ts | 4 +++ libs/ui/src/lib/value/value.component.ts | 9 ++++-- 10 files changed, 86 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd6113437..87ee49484 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 +### Changed + +- Improved the local number formatting in the value component + ### Fixed - Fixed the vertical alignment in the toggle component diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 4da329667..8af8e6ee2 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -20,9 +20,11 @@ import { encodeDataSource, extractNumberFromString } from '@ghostfolio/common/helper'; -import { InfoItem } from '@ghostfolio/common/interfaces'; -import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface'; -import { Subscription } from '@ghostfolio/common/interfaces/subscription.interface'; +import { + InfoItem, + Statistics, + Subscription +} from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; import { SubscriptionOffer } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index 591721f84..37b49ee34 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -4,7 +4,7 @@ import { DEFAULT_LANGUAGE_CODE, PROPERTY_STRIPE_CONFIG } from '@ghostfolio/common/config'; -import { Subscription as SubscriptionInterface } from '@ghostfolio/common/interfaces/subscription.interface'; +import { Subscription as SubscriptionInterface } from '@ghostfolio/common/interfaces'; import { UserWithSettings } from '@ghostfolio/common/types'; import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type'; import { Injectable, Logger } from '@nestjs/common'; diff --git a/apps/client/src/app/pages/about/about-page.component.ts b/apps/client/src/app/pages/about/about-page.component.ts index 59f247315..69f8eb093 100644 --- a/apps/client/src/app/pages/about/about-page.component.ts +++ b/apps/client/src/app/pages/about/about-page.component.ts @@ -3,8 +3,7 @@ import { environment } from '@ghostfolio/client/../environments/environment'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; -import { User } from '@ghostfolio/common/interfaces'; -import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface'; +import { Statistics, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; diff --git a/apps/client/src/app/pages/about/about-page.html b/apps/client/src/app/pages/about/about-page.html index ab8bd36cc..7c5702adb 100644 --- a/apps/client/src/app/pages/about/about-page.html +++ b/apps/client/src/app/pages/about/about-page.html @@ -6,12 +6,26 @@

Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make - solid, data-driven investment decisions. We share aggregated - open source software + (OSS) under the + AGPL-3.0 license + and we share aggregated + key metrics - of our platform’s performance and the source code is fully available - as open source software (OSS). The project has been initiated by + of the platform’s performance. The project has been initiated by Thomas Kaul @@ -130,6 +144,7 @@ Active Users @@ -138,6 +153,7 @@ New Users @@ -146,6 +162,7 @@ Active Users @@ -154,6 +171,7 @@ Users in Slack community @@ -166,6 +184,7 @@ > Contributors on GitHub @@ -178,6 +197,7 @@ > Stars on GitHub diff --git a/apps/client/src/app/pages/landing/landing-page.component.ts b/apps/client/src/app/pages/landing/landing-page.component.ts index 201105d46..453534299 100644 --- a/apps/client/src/app/pages/landing/landing-page.component.ts +++ b/apps/client/src/app/pages/landing/landing-page.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface'; +import { Statistics } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { format } from 'date-fns'; import { DeviceDetectorService } from 'ngx-device-detector'; diff --git a/apps/client/src/app/pages/open/open-page.component.ts b/apps/client/src/app/pages/open/open-page.component.ts index 554ab3bef..cf438a816 100644 --- a/apps/client/src/app/pages/open/open-page.component.ts +++ b/apps/client/src/app/pages/open/open-page.component.ts @@ -1,7 +1,8 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface'; -import { Subject } from 'rxjs'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { Statistics, User } from '@ghostfolio/common/interfaces'; +import { Subject, takeUntil } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -11,16 +12,31 @@ import { Subject } from 'rxjs'; }) export class OpenPageComponent implements OnDestroy, OnInit { public statistics: Statistics; + public user: User; private unsubscribeSubject = new Subject(); - public constructor(private dataService: DataService) { + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private dataService: DataService, + private userService: UserService + ) { const { statistics } = this.dataService.fetchInfo(); this.statistics = statistics; } - public ngOnInit() {} + public ngOnInit() { + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + + this.changeDetectorRef.markForCheck(); + } + }); + } public ngOnDestroy() { this.unsubscribeSubject.next(); diff --git a/apps/client/src/app/pages/open/open-page.html b/apps/client/src/app/pages/open/open-page.html index 2de588429..81b4dcd4e 100644 --- a/apps/client/src/app/pages/open/open-page.html +++ b/apps/client/src/app/pages/open/open-page.html @@ -4,15 +4,21 @@

Open Startup

@@ -27,6 +33,7 @@ Active Users @@ -35,6 +42,7 @@ New Users @@ -43,6 +51,7 @@ Active Users @@ -51,6 +60,7 @@ Users in Slack community @@ -63,6 +73,7 @@ > Contributors on GitHub @@ -75,6 +86,7 @@ > Stars on GitHub @@ -87,6 +99,7 @@ > Pulls on Docker Hub @@ -97,6 +110,7 @@ Uptime Date: Sat, 20 May 2023 11:07:53 +0200 Subject: [PATCH 03/18] Feature/change uptime to last 90 days (#1993) * Change uptime to last 90 days * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/info/info.service.ts | 8 ++++++-- apps/client/src/app/pages/open/open-page.html | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ee49484..695f93110 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the local number formatting in the value component +- Changed the uptime to the last 90 days on the _Open Startup_ (`/open`) page ### Fixed diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 8af8e6ee2..187135a35 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -17,6 +17,7 @@ import { ghostfolioFearAndGreedIndexDataSource } from '@ghostfolio/common/config'; import { + DATE_FORMAT, encodeDataSource, extractNumberFromString } from '@ghostfolio/common/helper'; @@ -31,7 +32,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bent from 'bent'; import * as cheerio from 'cheerio'; -import { subDays } from 'date-fns'; +import { format, subDays } from 'date-fns'; @Injectable() export class InfoService { @@ -346,7 +347,10 @@ export class InfoService { )) as string; const get = bent( - `https://betteruptime.com/api/v2/monitors/${monitorId}/sla`, + `https://betteruptime.com/api/v2/monitors/${monitorId}/sla?from=${format( + subDays(new Date(), 90), + DATE_FORMAT + )}&to${format(new Date(), DATE_FORMAT)}`, 'GET', 'json', 200, diff --git a/apps/client/src/app/pages/open/open-page.html b/apps/client/src/app/pages/open/open-page.html index 81b4dcd4e..62503e387 100644 --- a/apps/client/src/app/pages/open/open-page.html +++ b/apps/client/src/app/pages/open/open-page.html @@ -109,6 +109,7 @@ Date: Sat, 20 May 2023 11:10:07 +0200 Subject: [PATCH 04/18] Feature/extend financial modeling prep service (#1989) * Add getHistorical() and search() logic * Update changelog --- CHANGELOG.md | 4 ++ .../financial-modeling-prep.service.ts | 68 +++++++++++++++++-- .../yahoo-finance/yahoo-finance.service.ts | 3 +- .../api/src/services/interfaces/interfaces.ts | 1 - 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 695f93110..70a2ab12f 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 + +- Added the historical data and search functionality for the `FINANCIAL_MODELING_PREP` data source type + ### Changed - Improved the local number formatting in the value component diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index d4fe3325b..bcee3c5e7 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -5,11 +5,13 @@ import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; +import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; import { DataProviderInfo } from '@ghostfolio/common/interfaces'; import { Granularity } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import bent from 'bent'; +import { format, isAfter, isBefore, isSameDay } from 'date-fns'; @Injectable() export class FinancialModelingPrepService implements DataProviderInterface { @@ -61,9 +63,42 @@ export class FinancialModelingPrepService implements DataProviderInterface { ): Promise<{ [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; }> { - return { - [aSymbol]: {} - }; + try { + const get = bent( + `${this.URL}/historical-price-full/${aSymbol}?apikey=${this.apiKey}`, + 'GET', + 'json', + 200 + ); + const { historical } = await get(); + + const result: { + [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; + } = { + [aSymbol]: {} + }; + + for (const { close, date } of historical) { + if ( + (isSameDay(parseDate(date), from) || + isAfter(parseDate(date), from)) && + isBefore(parseDate(date), to) + ) { + result[aSymbol][date] = { + marketPrice: close + }; + } + } + + return result; + } catch (error) { + throw new Error( + `Could not get historical market data for ${aSymbol} (${this.getName()}) from ${format( + from, + DATE_FORMAT + )} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}` + ); + } } public getName(): DataSource { @@ -109,7 +144,32 @@ export class FinancialModelingPrepService implements DataProviderInterface { } public async search(aQuery: string): Promise<{ items: LookupItem[] }> { - return { items: [] }; + let items: LookupItem[] = []; + + try { + const get = bent( + `${this.URL}/search?query=${aQuery}&apikey=${this.apiKey}`, + 'GET', + 'json', + 200 + ); + const result = await get(); + + items = result.map(({ currency, name, symbol }) => { + return { + // TODO: Add assetClass + // TODO: Add assetSubClass + currency, + name, + symbol, + dataSource: this.getName() + }; + }); + } catch (error) { + Logger.error(error, 'FinancialModelingPrepService'); + } + + return { items }; } private getDataProviderInfo(): DataProviderInfo { diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index b0d94baf6..e47713680 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -138,8 +138,7 @@ export class YahooFinanceService implements DataProviderInterface { marketPrice: this.getConvertedValue({ symbol: aSymbol, value: historicalItem.close - }), - performance: historicalItem.open - historicalItem.close + }) }; } diff --git a/apps/api/src/services/interfaces/interfaces.ts b/apps/api/src/services/interfaces/interfaces.ts index 58f25243c..15505db63 100644 --- a/apps/api/src/services/interfaces/interfaces.ts +++ b/apps/api/src/services/interfaces/interfaces.ts @@ -23,7 +23,6 @@ export interface IOrder { export interface IDataProviderHistoricalResponse { marketPrice: number; - performance?: number; } export interface IDataProviderResponse { From 51e36507901d00e782d27c91911815e2d1c57357 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 20 May 2023 18:12:12 +0200 Subject: [PATCH 05/18] Feature/add blog post unlock your financial potential (#1994) * Add blog post: Unlock your Financial Potential with Ghostfolio * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/frontend.middleware.ts | 7 + apps/client/src/app/app-routing.module.ts | 7 + ...ial-with-ghostfolio-page-routing.module.ts | 20 ++ ...otential-with-ghostfolio-page.component.ts | 9 + ...ancial-potential-with-ghostfolio-page.html | 238 ++++++++++++++++++ ...l-potential-with-ghostfolio-page.module.ts | 19 ++ ...ancial-potential-with-ghostfolio-page.scss | 3 + apps/client/src/app/pages/blog/blog-page.html | 26 ++ .../src/assets/images/blog/20230520.jpg | Bin 0 -> 105318 bytes apps/client/src/assets/sitemap.xml | 56 +++-- 11 files changed, 360 insertions(+), 26 deletions(-) create mode 100644 apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page-routing.module.ts create mode 100644 apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts create mode 100644 apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html create mode 100644 apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.module.ts create mode 100644 apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.scss create mode 100644 apps/client/src/assets/images/blog/20230520.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a2ab12f..88fdc2dd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added the historical data and search functionality for the `FINANCIAL_MODELING_PREP` data source type +- Added a blog post: _Unlock your Financial Potential with Ghostfolio_ ### Changed diff --git a/apps/api/src/app/frontend.middleware.ts b/apps/api/src/app/frontend.middleware.ts index 58e39a5ea..b028f7996 100644 --- a/apps/api/src/app/frontend.middleware.ts +++ b/apps/api/src/app/frontend.middleware.ts @@ -94,6 +94,13 @@ export class FrontendMiddleware implements NestMiddleware { ) { featureGraphicPath = 'assets/images/blog/1000-stars-on-github.jpg'; title = `Ghostfolio reaches 1’000 Stars on GitHub - ${title}`; + } else if ( + request.path.startsWith( + '/en/blog/2023/05/unlock-your-financial-potential-with-ghostfolio' + ) + ) { + featureGraphicPath = 'assets/images/blog/20230520.jpg'; + title = `Unlock your Financial Potential with Ghostfolio - ${title}`; } if ( diff --git a/apps/client/src/app/app-routing.module.ts b/apps/client/src/app/app-routing.module.ts index 0f6acd870..b4b2792b8 100644 --- a/apps/client/src/app/app-routing.module.ts +++ b/apps/client/src/app/app-routing.module.ts @@ -137,6 +137,13 @@ const routes: Routes = [ './pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.module' ).then((m) => m.ThousandStarsOnGitHubPageModule) }, + { + path: 'blog/2023/05/unlock-your-financial-potential-with-ghostfolio', + loadChildren: () => + import( + './pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.module' + ).then((m) => m.UnlockYourFinancialPotentialWithGhostfolioPageModule) + }, { path: 'demo', loadChildren: () => diff --git a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page-routing.module.ts b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page-routing.module.ts new file mode 100644 index 000000000..355e8b714 --- /dev/null +++ b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page-routing.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; + +import { UnlockYourFinancialPotentialWithGhostfolioPageComponent } from './unlock-your-financial-potential-with-ghostfolio-page.component'; + +const routes: Routes = [ + { + canActivate: [AuthGuard], + component: UnlockYourFinancialPotentialWithGhostfolioPageComponent, + path: '', + title: 'Unlock your Financial Potential with Ghostfolio' + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class UnlockYourFinancialPotentialWithGhostfolioRoutingModule {} diff --git a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts new file mode 100644 index 000000000..313642587 --- /dev/null +++ b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + host: { class: 'page' }, + selector: 'gf-unlock-your-financial-potential-with-ghostfolio-page', + styleUrls: ['./unlock-your-financial-potential-with-ghostfolio-page.scss'], + templateUrl: './unlock-your-financial-potential-with-ghostfolio-page.html' +}) +export class UnlockYourFinancialPotentialWithGhostfolioPageComponent {} diff --git a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html new file mode 100644 index 000000000..6170394f5 --- /dev/null +++ b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html @@ -0,0 +1,238 @@ +
+
+
+
+
+

Unlock your Financial Potential with Ghostfolio

+
2023-05-20
+ Unlock your financial potential with Ghostfolio Teaser +
+
+

+ Managing personal finances effectively is crucial for those striving + for financial independence and a secure future. In today’s digital + age, having a reliable personal finance software can greatly + simplify the process. Ghostfolio is a powerful + open source solution + for individuals trading stocks, ETFs, or cryptocurrencies on + multiple platforms. This article explores the key reasons why + Ghostfolio is the ideal choice for those embracing minimalism, + pursuing a buy & hold strategy, seeking portfolio insights, and + diversifying financial resources while valuing privacy. +

+
+
+

Effortless Management for Multi-Platform Investors

+

+ Ghostfolio offers a consolidated solution to efficiently monitor and + manage investment portfolios across multiple platforms. By + consolidating data from various accounts, Ghostfolio eliminates the + need to switch between platforms, saving users valuable time and + effort. +

+
+
+

Empowering Buy & Hold Strategies

+

+ For those committed to a + buy & hold strategy, Ghostfolio + provides an intuitive interface to monitor long-term investments. + Users can track performance over time, gaining insights into + portfolio growth and stability. With strong visualizations and + reporting features, Ghostfolio + equips users to make well-informed decisions aligned with their + long-term investment goals. +

+
+
+

Deep Portfolio Insights

+

+ Understanding portfolio composition is vital for making informed + financial decisions. Ghostfolio provides comprehensive insights into + asset allocation, sector exposure, geographical diversification, and + individual asset performance. These detailed analytics empower users + to assess portfolio strengths and weaknesses, making necessary + adjustments to optimize their diversification. +

+
+
+

Privacy and Data Ownership

+

+ In the age of growing data security concerns, Ghostfolio sets itself + apart by giving the highest priority to privacy and data ownership. + As an open-source software, Ghostfolio ensures that users retain + complete control over their financial data. By eliminating the need + to trust third-party platforms with sensitive information, + Ghostfolio offers peace of mind to those who value privacy and data + security. +

+
+
+

Streamlined Minimalism for Financial Efficiency

+

+ Ghostfolio embraces a minimalist approach to personal finance + management, focusing on essential features without overwhelming + users. Its streamlined user interface and clean design provide a + seamless and clutter-free experience. This minimalist approach + enhances user satisfaction and boosts efficiency by eliminating + distractions and simplifying the financial management process. +

+
+
+

Driving Financial Independence (FIRE)

+

+ Achieving + financial independence + including early retirement (FIRE) requires careful planning, + monitoring, and forecasting. Ghostfolio’s robust features equip + individuals with tools to analyze, optimize and simulate investment + strategies. By providing insights, performance tracking, and + portfolio analysis, Ghostfolio serves as a valuable companion in the + pursuit of financial freedom. +

+
+
+

Farewell to Spreadsheet Hassles

+

+ While spreadsheets have traditionally been used to manage personal + finances, they can be time-consuming and prone to errors. Ghostfolio + offers a user-friendly alternative by automating data aggregation, + analysis, and reporting. Users can bid farewell to manual data entry + and complex formulas, relying instead on Ghostfolio’s user-friendly + and intuitive interface to efficiently manage their finances. +

+
+
+

Your Path to Financial Success with Ghostfolio

+

+ Ghostfolio, the open-source personal finance software, provides a + wide range of benefits for individuals involved in trading stocks, + ETFs, or cryptocurrencies. Whether you are pursuing a buy & hold + strategy, seeking valuable portfolio insights, or diversifying + financial resources while prioritizing privacy and data ownership, + Ghostfolio proves to be an invaluable tool on your journey towards + unlocking your financial potential. Say goodbye to spreadsheets and + embrace the power of Ghostfolio for simplified, secure, and + successful financial management. +

+
+
+

+ Would you like to unlock your + financial potential? +

+

+ Ghostfolio empowers you to manage your personal finances + effectively. +

+ +
+
+
    +
  • + App +
  • +
  • + Analysis +
  • +
  • + Assets +
  • +
  • + Budgeting +
  • +
  • + Buy & Hold +
  • +
  • + Cryptocurrencies +
  • +
  • + Diversification +
  • +
  • + ETFs +
  • +
  • + Finance +
  • +
  • + Fintech +
  • +
  • + Ghostfolio +
  • +
  • + Investment +
  • +
  • + Management +
  • +
  • + Minimalism +
  • +
  • + Monitoring +
  • +
  • + Open Source +
  • +
  • + Personal Finance +
  • +
  • + Planning +
  • +
  • + Portfolio Tracker +
  • +
  • + Privacy +
  • +
  • + Retirement +
  • +
  • + Software +
  • +
  • + Spreadsheet +
  • +
  • + Stock +
  • +
  • + Strategy +
  • +
  • + Wealth +
  • +
+
+ +
+
+
+
diff --git a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.module.ts b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.module.ts new file mode 100644 index 000000000..7aeb7f1a2 --- /dev/null +++ b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.module.ts @@ -0,0 +1,19 @@ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { RouterModule } from '@angular/router'; + +import { UnlockYourFinancialPotentialWithGhostfolioRoutingModule } from './unlock-your-financial-potential-with-ghostfolio-page-routing.module'; +import { UnlockYourFinancialPotentialWithGhostfolioPageComponent } from './unlock-your-financial-potential-with-ghostfolio-page.component'; + +@NgModule({ + declarations: [UnlockYourFinancialPotentialWithGhostfolioPageComponent], + imports: [ + CommonModule, + MatButtonModule, + RouterModule, + UnlockYourFinancialPotentialWithGhostfolioRoutingModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class UnlockYourFinancialPotentialWithGhostfolioPageModule {} diff --git a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.scss b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.scss new file mode 100644 index 000000000..5d4e87f30 --- /dev/null +++ b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/client/src/app/pages/blog/blog-page.html b/apps/client/src/app/pages/blog/blog-page.html index e0808556e..dd663fe05 100644 --- a/apps/client/src/app/pages/blog/blog-page.html +++ b/apps/client/src/app/pages/blog/blog-page.html @@ -2,6 +2,32 @@

Blog

+ + + + +
diff --git a/apps/client/src/assets/images/blog/20230520.jpg b/apps/client/src/assets/images/blog/20230520.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd170944e3419b417114563c85b4705a5f339641 GIT binary patch literal 105318 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 &TMK@ax#mCp#B5`S=bsE{eW^ik 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 https://ghostfol.io - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/de/blog - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/de/blog/2021/07/hallo-ghostfolio - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/de/pricing - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/about - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/about/changelog - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2021/07/hello-ghostfolio - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/01/ghostfolio-first-months-in-open-source - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/07/ghostfolio-meets-internet-identity - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/07/how-do-i-get-my-finances-in-order - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/08/500-stars-on-github - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/10/hacktoberfest-2022 - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/11/black-friday-2022 - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2022/12/the-importance-of-tracking-your-personal-finances - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2023/02/ghostfolio-meets-umbrel - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/blog/2023/03/ghostfolio-reaches-1000-stars-on-github - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 + + + https://ghostfol.io/en/blog/2023/05/unlock-your-financial-potential-with-ghostfolio + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/demo - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/faq - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/features - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/markets - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/open - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/pricing - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/register - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 https://ghostfol.io/en/resources - 2023-05-15T00:00:00+00:00 + 2023-05-20T00:00:00+00:00 From d0ccd4d238c690c46ea0c2ffc2f23a04a2a466aa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 20 May 2023 18:13:41 +0200 Subject: [PATCH 06/18] Release 1.271.0 (#1995) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88fdc2dd1..39c7b5e43 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 +## 1.271.0 - 2023-05-20 ### Added diff --git a/package.json b/package.json index 3ec808f90..1ac97aa95 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "1.270.1", + "version": "1.271.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "scripts": { From faef3606fd1e98c82760e5f8a534a34e2dc08109 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 21 May 2023 07:50:45 +0200 Subject: [PATCH 07/18] Feature/improve breadcrumb navigation style in blog posts for mobile (#1996) * Improve style for mobile * Update changelog --- CHANGELOG.md | 6 +++++ .../hallo-ghostfolio-page.html | 5 +++- .../hello-ghostfolio-page.html | 5 +++- .../first-months-in-open-source-page.html | 5 +++- ...ostfolio-meets-internet-identity-page.html | 5 +++- ...ow-do-i-get-my-finances-in-order-page.html | 5 +++- .../500-stars-on-github-page.html | 5 +++- .../hacktoberfest-2022-page.html | 5 +++- .../black-friday-2022-page.html | 5 +++- ...-tracking-your-personal-finances-page.html | 5 +++- ...stfolio-auf-sackgeld-vorgestellt-page.html | 5 +++- .../ghostfolio-meets-umbrel-page.html | 5 +++- .../1000-stars-on-github-page.html | 5 +++- ...ancial-potential-with-ghostfolio-page.html | 24 ++++++++++++------- apps/client/src/styles.scss | 3 +++ 15 files changed, 72 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c7b5e43..b00cfdb28 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 breadcrumb navigation style in the blog post pages for mobile + ## 1.271.0 - 2023-05-20 ### Added diff --git a/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html b/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html index ae03b1e72..b5c535462 100644 --- a/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html +++ b/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -202,7 +202,10 @@ - diff --git a/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.html b/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.html index 891d91631..e10e75b79 100644 --- a/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.html +++ b/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.html @@ -182,7 +182,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.html b/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.html index 902aee546..d7b498a11 100644 --- a/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.html +++ b/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.html @@ -179,7 +179,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.html b/apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.html index 54ede8fef..b78010dd4 100644 --- a/apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.html +++ b/apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.html @@ -182,7 +182,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.html b/apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.html index 72dec1fad..a9c0085fe 100644 --- a/apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.html +++ b/apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.html @@ -208,7 +208,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.html b/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.html index 474ec4a04..21098139a 100644 --- a/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.html +++ b/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.html @@ -191,7 +191,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.html b/apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.html index 788cc8115..46792b5b3 100644 --- a/apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.html +++ b/apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.html @@ -177,7 +177,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.html b/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.html index 53726b54c..50476e70e 100644 --- a/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.html +++ b/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.html @@ -137,7 +137,10 @@ - diff --git a/apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.html b/apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.html index bbaa3d4c4..ed87c7913 100644 --- a/apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.html +++ b/apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.html @@ -167,7 +167,10 @@ - diff --git a/apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.html b/apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.html index 4145657fe..4da21fafa 100644 --- a/apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.html +++ b/apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.html @@ -177,7 +177,10 @@ - diff --git a/apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.html b/apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.html index 0191d777e..13eff6898 100644 --- a/apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.html +++ b/apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.html @@ -199,7 +199,10 @@ - diff --git a/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html b/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html index ce0dbe16e..9e1ae8a74 100644 --- a/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html +++ b/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html @@ -244,7 +244,10 @@ - diff --git a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html index 6170394f5..d6226dafe 100644 --- a/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html +++ b/apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html @@ -15,8 +15,8 @@

Managing personal finances effectively is crucial for those striving - for financial independence and a secure future. In today’s digital - age, having a reliable personal finance software can greatly + for a secure future and financial independence. In today’s digital + age, having a reliable wealth management software can greatly simplify the process. Ghostfolio is a powerful for individuals trading stocks, ETFs, or cryptocurrencies on multiple platforms. This article explores the key reasons why - Ghostfolio is the ideal choice for those embracing minimalism, - pursuing a buy & hold strategy, seeking portfolio insights, and - diversifying financial resources while valuing privacy. + Ghostfolio is the ideal choice for those embracing diversification, + pursuing a buy & hold strategy, and seeking portfolio insights while + valuing privacy.

Effortless Management for Multi-Platform Investors

- Ghostfolio offers a consolidated solution to efficiently monitor and + Ghostfolio offers a holistic solution to efficiently monitor and manage investment portfolios across multiple platforms. By consolidating data from various accounts, Ghostfolio eliminates the need to switch between platforms, saving users valuable time and @@ -61,7 +61,7 @@ asset allocation, sector exposure, geographical diversification, and individual asset performance. These detailed analytics empower users to assess portfolio strengths and weaknesses, making necessary - adjustments to optimize their diversification. + adjustments to optimize their allocation.

@@ -79,7 +79,7 @@

Streamlined Minimalism for Financial Efficiency

- Ghostfolio embraces a minimalist approach to personal finance + Ghostfolio embraces a lightweight approach to personal finance management, focusing on essential features without overwhelming users. Its streamlined user interface and clean design provide a seamless and clutter-free experience. This minimalist approach @@ -172,6 +172,9 @@

  • Fintech
  • +
  • + FIRE +
  • Ghostfolio
  • @@ -227,7 +230,10 @@
    - diff --git a/apps/client/src/styles.scss b/apps/client/src/styles.scss index 942e75294..a84fbab03 100644 --- a/apps/client/src/styles.scss +++ b/apps/client/src/styles.scss @@ -327,10 +327,13 @@ ngx-skeleton-loader { .breadcrumb { background-color: unset; + flex-wrap: nowrap; padding: unset; } .breadcrumb-item { + flex-wrap: nowrap; + &.active { color: unset; } From 7bf48ef35139edbf35a8b421d84f4d4ea56cbd18 Mon Sep 17 00:00:00 2001 From: secondl1ght <85003930+secondl1ght@users.noreply.github.com> Date: Mon, 22 May 2023 12:20:16 -0600 Subject: [PATCH 08/18] Improve style on about page (#1998) * Center changelog button * Update changelog --- CHANGELOG.md | 1 + apps/client/src/app/pages/about/about-page.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b00cfdb28..68ea155bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the breadcrumb navigation style in the blog post pages for mobile +- Improved the style of the _Changelog & License_ button on the about page ## 1.271.0 - 2023-05-20 diff --git a/apps/client/src/app/pages/about/about-page.html b/apps/client/src/app/pages/about/about-page.html index 7c5702adb..6b19aba77 100644 --- a/apps/client/src/app/pages/about/about-page.html +++ b/apps/client/src/app/pages/about/about-page.html @@ -221,7 +221,7 @@
    Date: Tue, 23 May 2023 14:45:21 +0200 Subject: [PATCH 09/18] Feature/upgrade ionicons to version 7.1.0 (#1997) * Upgrade ionicons to version 7.1.0 * Update changelog --- CHANGELOG.md | 1 + package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68ea155bc..98cc84059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the breadcrumb navigation style in the blog post pages for mobile - Improved the style of the _Changelog & License_ button on the about page +- Upgraded `ionicons` from version `6.1.2` to `7.1.0` ## 1.271.0 - 2023-05-20 diff --git a/package.json b/package.json index 1ac97aa95..bac60f0cc 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "envalid": "7.3.1", "google-spreadsheet": "3.2.0", "http-status-codes": "2.2.0", - "ionicons": "6.1.2", + "ionicons": "7.1.0", "lodash": "4.17.21", "marked": "4.2.12", "ms": "3.0.0-canary.1", diff --git a/yarn.lock b/yarn.lock index 4e9fc465f..224e66b60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11221,10 +11221,10 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== -ionicons@6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/ionicons/-/ionicons-6.1.2.tgz#805ed1ce272b653ac07a85f83514e5afa2c9677d" - integrity sha512-EL3jjlUzjPo8h2PfI+BUEjVMF9weSfLAFriNlk9pHFMTJq+7G12sAJBZ3AnRN8nTWA2pOS279PvFIWS3hbat+w== +ionicons@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/ionicons/-/ionicons-7.1.0.tgz#25daa91345acedcb0f4fb7da670f5aff2e1f266a" + integrity sha512-iE4GuEdEHARJpp0sWL7WJZCzNCf5VxpNRhAjW0fLnZPnNL5qZOJUcfup2Z2Ty7Jk8Q5hacrHfGEB1lCwOdXqGg== dependencies: "@stencil/core" "^2.18.0" From 1916e5343dc5ad7661334e287345ede48cc68671 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 24 May 2023 19:34:12 +0200 Subject: [PATCH 10/18] Feature/decrease table density (#2001) * Decrease table density * Update changelog --- CHANGELOG.md | 3 ++- apps/client/src/styles/theme.scss | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98cc84059..ef017ba04 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 +- Decreased the density of the `@angular/material` tables - Improved the breadcrumb navigation style in the blog post pages for mobile - Improved the style of the _Changelog & License_ button on the about page - Upgraded `ionicons` from version `6.1.2` to `7.1.0` @@ -271,7 +272,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed the slide toggles to checkboxes on the account page - Changed the slide toggles to checkboxes in the admin control panel -- Decreased the density of the theme +- Increased the density of the theme - Migrated the style of various components to `@angular/material` `15` (mdc) - Upgraded `@angular/cdk` and `@angular/material` from version `15.2.5` to `15.2.6` - Upgraded `bull` from version `4.10.2` to `4.10.4` diff --git a/apps/client/src/styles/theme.scss b/apps/client/src/styles/theme.scss index 118d53336..5dcbb10ff 100644 --- a/apps/client/src/styles/theme.scss +++ b/apps/client/src/styles/theme.scss @@ -86,6 +86,7 @@ $gf-theme-default: mat.define-light-theme( ); @include mat.all-component-themes($gf-theme-default); @include mat.button-density(0); +@include mat.table-density(-1); // Create dark theme $gf-theme-dark: mat.define-dark-theme( @@ -101,6 +102,7 @@ $gf-theme-dark: mat.define-dark-theme( .is-dark-theme { @include mat.all-component-colors($gf-theme-dark); @include mat.button-density(0); + @include mat.table-density(-1); } :root { From 215f5eafa64aa2e6f2c15acbeeaa05dc55ccb715 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 24 May 2023 21:22:32 +0200 Subject: [PATCH 11/18] Feature/set asset profile as benchmark (#2002) * Set asset profile as benchmark * Update changelog Co-authored-by: Arghya Ghosh --- CHANGELOG.md | 4 ++ .../src/app/benchmark/benchmark.controller.ts | 53 ++++++++++++++++++- .../api/src/app/benchmark/benchmark.module.ts | 2 + .../app/benchmark/benchmark.service.spec.ts | 10 +++- .../src/app/benchmark/benchmark.service.ts | 47 ++++++++++++++-- .../admin-market-data/admin-market-data.html | 12 ----- .../asset-profile-dialog.component.ts | 23 +++++++- .../asset-profile-dialog.html | 7 +++ apps/client/src/app/services/data.service.ts | 4 ++ .../benchmark-property.interface.ts | 3 ++ libs/common/src/lib/interfaces/index.ts | 2 + 11 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 libs/common/src/lib/interfaces/benchmark-property.interface.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index ef017ba04..662e1f3cf 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 + +- Added support to set an asset profile as a benchmark + ### Changed - Decreased the density of the `@angular/material` tables diff --git a/apps/api/src/app/benchmark/benchmark.controller.ts b/apps/api/src/app/benchmark/benchmark.controller.ts index 4daa14009..91426090e 100644 --- a/apps/api/src/app/benchmark/benchmark.controller.ts +++ b/apps/api/src/app/benchmark/benchmark.controller.ts @@ -2,23 +2,35 @@ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interce import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor'; import { BenchmarkMarketDataDetails, - BenchmarkResponse + BenchmarkResponse, + UniqueAsset } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { + Body, Controller, Get, + HttpException, + Inject, Param, + Post, UseGuards, UseInterceptors } from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { DataSource } from '@prisma/client'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { BenchmarkService } from './benchmark.service'; @Controller('benchmark') export class BenchmarkController { - public constructor(private readonly benchmarkService: BenchmarkService) {} + public constructor( + private readonly benchmarkService: BenchmarkService, + @Inject(REQUEST) private readonly request: RequestWithUser + ) {} @Get() @UseInterceptors(TransformDataSourceInRequestInterceptor) @@ -45,4 +57,41 @@ export class BenchmarkController { symbol }); } + + @Post() + @UseGuards(AuthGuard('jwt')) + public async addBenchmark(@Body() { dataSource, symbol }: UniqueAsset) { + if ( + !hasPermission( + this.request.user.permissions, + permissions.accessAdminControl + ) + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + + try { + const benchmark = await this.benchmarkService.addBenchmark({ + dataSource, + symbol + }); + + if (!benchmark) { + throw new HttpException( + getReasonPhrase(StatusCodes.NOT_FOUND), + StatusCodes.NOT_FOUND + ); + } + + return benchmark; + } catch { + throw new HttpException( + getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR), + StatusCodes.INTERNAL_SERVER_ERROR + ); + } + } } diff --git a/apps/api/src/app/benchmark/benchmark.module.ts b/apps/api/src/app/benchmark/benchmark.module.ts index 71b08c191..c2cc3fbb5 100644 --- a/apps/api/src/app/benchmark/benchmark.module.ts +++ b/apps/api/src/app/benchmark/benchmark.module.ts @@ -3,6 +3,7 @@ import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.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'; @@ -17,6 +18,7 @@ import { BenchmarkService } from './benchmark.service'; ConfigurationModule, DataProviderModule, MarketDataModule, + PrismaModule, PropertyModule, RedisCacheModule, SymbolModule, diff --git a/apps/api/src/app/benchmark/benchmark.service.spec.ts b/apps/api/src/app/benchmark/benchmark.service.spec.ts index 833dbcdfc..5fa2c3e7b 100644 --- a/apps/api/src/app/benchmark/benchmark.service.spec.ts +++ b/apps/api/src/app/benchmark/benchmark.service.spec.ts @@ -4,7 +4,15 @@ describe('BenchmarkService', () => { let benchmarkService: BenchmarkService; beforeAll(async () => { - benchmarkService = new BenchmarkService(null, null, null, null, null, null); + benchmarkService = new BenchmarkService( + null, + null, + null, + null, + null, + null, + null + ); }); it('calculateChangeInPercentage', async () => { diff --git a/apps/api/src/app/benchmark/benchmark.service.ts b/apps/api/src/app/benchmark/benchmark.service.ts index 4e87b26f9..73b48068b 100644 --- a/apps/api/src/app/benchmark/benchmark.service.ts +++ b/apps/api/src/app/benchmark/benchmark.service.ts @@ -2,6 +2,7 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.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'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { @@ -11,6 +12,7 @@ import { import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { BenchmarkMarketDataDetails, + BenchmarkProperty, BenchmarkResponse, UniqueAsset } from '@ghostfolio/common/interfaces'; @@ -18,6 +20,7 @@ import { Injectable } from '@nestjs/common'; import { SymbolProfile } from '@prisma/client'; import Big from 'big.js'; import { format } from 'date-fns'; +import { uniqBy } from 'lodash'; import ms from 'ms'; @Injectable() @@ -27,6 +30,7 @@ export class BenchmarkService { public constructor( private readonly dataProviderService: DataProviderService, private readonly marketDataService: MarketDataService, + private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly redisCacheService: RedisCacheService, private readonly symbolProfileService: SymbolProfileService, @@ -116,9 +120,9 @@ export class BenchmarkService { public async getBenchmarkAssetProfiles(): Promise[]> { const symbolProfileIds: string[] = ( - ((await this.propertyService.getByKey(PROPERTY_BENCHMARKS)) as { - symbolProfileId: string; - }[]) ?? [] + ((await this.propertyService.getByKey( + PROPERTY_BENCHMARKS + )) as BenchmarkProperty[]) ?? [] ).map(({ symbolProfileId }) => { return symbolProfileId; }); @@ -204,6 +208,43 @@ export class BenchmarkService { return response; } + public async addBenchmark({ + dataSource, + symbol + }: UniqueAsset): Promise> { + const assetProfile = await this.prismaService.symbolProfile.findFirst({ + where: { + dataSource, + symbol + } + }); + + if (!assetProfile) { + return; + } + + let benchmarks = + ((await this.propertyService.getByKey( + PROPERTY_BENCHMARKS + )) as BenchmarkProperty[]) ?? []; + + benchmarks.push({ symbolProfileId: assetProfile.id }); + + benchmarks = uniqBy(benchmarks, 'symbolProfileId'); + + await this.propertyService.put({ + key: PROPERTY_BENCHMARKS, + value: JSON.stringify(benchmarks) + }); + + return { + dataSource, + symbol, + id: assetProfile.id, + name: assetProfile.name + }; + } + private getMarketCondition(aPerformanceInPercent: number) { return aPerformanceInPercent <= -0.2 ? 'BEAR_MARKET' : 'NEUTRAL_MARKET'; } diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.html b/apps/client/src/app/components/admin-market-data/admin-market-data.html index 36beae6dd..bb9322a68 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.html +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -143,18 +143,6 @@ - - +
    diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index bff672717..32e7ba7ae 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -405,6 +405,10 @@ export class DataService { return this.http.post(`/api/v1/account`, aAccount); } + public postBenchmark(benchmark: UniqueAsset) { + return this.http.post(`/api/v1/benchmark`, benchmark); + } + public postOrder(aOrder: CreateOrderDto) { return this.http.post(`/api/v1/order`, aOrder); } diff --git a/libs/common/src/lib/interfaces/benchmark-property.interface.ts b/libs/common/src/lib/interfaces/benchmark-property.interface.ts new file mode 100644 index 000000000..bccf4ed78 --- /dev/null +++ b/libs/common/src/lib/interfaces/benchmark-property.interface.ts @@ -0,0 +1,3 @@ +export interface BenchmarkProperty { + symbolProfileId: string; +} diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index b6b1e79c7..538615861 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -8,6 +8,7 @@ import { AdminMarketDataItem } from './admin-market-data.interface'; import { BenchmarkMarketDataDetails } from './benchmark-market-data-details.interface'; +import { BenchmarkProperty } from './benchmark-property.interface'; import { Benchmark } from './benchmark.interface'; import { Coupon } from './coupon.interface'; import { DataProviderInfo } from './data-provider-info.interface'; @@ -54,6 +55,7 @@ export { AdminMarketDataItem, Benchmark, BenchmarkMarketDataDetails, + BenchmarkProperty, BenchmarkResponse, Coupon, DataProviderInfo, From 1f393e78f68d2f3675605341860daf4ef56fca8e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 25 May 2023 17:27:33 +0200 Subject: [PATCH 12/18] Feature/improve error handling in delete user endpoint (#2000) * Improve error handling * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/user/user.service.ts | 32 +++++++++++++++++---------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 662e1f3cf..8f465d45b 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 - Decreased the density of the `@angular/material` tables - Improved the breadcrumb navigation style in the blog post pages for mobile +- Improved the error handling in the delete user endpoint - Improved the style of the _Changelog & License_ button on the about page - Upgraded `ionicons` from version `6.1.2` to `7.1.0` diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 56807e10a..26736e88d 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -304,21 +304,29 @@ export class UserService { } public async deleteUser(where: Prisma.UserWhereUniqueInput): Promise { - await this.prismaService.access.deleteMany({ - where: { OR: [{ granteeUserId: where.id }, { userId: where.id }] } - }); + try { + await this.prismaService.access.deleteMany({ + where: { OR: [{ granteeUserId: where.id }, { userId: where.id }] } + }); + } catch {} - await this.prismaService.account.deleteMany({ - where: { userId: where.id } - }); + try { + await this.prismaService.account.deleteMany({ + where: { userId: where.id } + }); + } catch {} - await this.prismaService.analytics.delete({ - where: { userId: where.id } - }); + try { + await this.prismaService.analytics.delete({ + where: { userId: where.id } + }); + } catch {} - await this.prismaService.order.deleteMany({ - where: { userId: where.id } - }); + try { + await this.prismaService.order.deleteMany({ + where: { userId: where.id } + }); + } catch {} try { await this.prismaService.settings.delete({ From b3baeb8a5d56b2f4fe7ae60825eb987be4f48b79 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 26 May 2023 20:41:33 +0200 Subject: [PATCH 13/18] Feature/support case insensitive names in portfolio proportion chart (#2004) * Sum up case insensitive names * Update changelog --- CHANGELOG.md | 1 + .../portfolio-proportion-chart.component.ts | 50 ++++++++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f465d45b..0d716e7c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Decreased the density of the `@angular/material` tables +- Improved the portfolio proportion chart component by supporting case insensitive names - Improved the breadcrumb navigation style in the blog post pages for mobile - Improved the error handling in the delete user endpoint - Improved the style of the _Changelog & License_ button on the about page 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 36991d763..452cd8f35 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 @@ -100,38 +100,42 @@ export class PortfolioProportionChartComponent }; Object.keys(this.positions).forEach((symbol) => { - if (this.positions[symbol][this.keys[0]]) { - if (chartData[this.positions[symbol][this.keys[0]]]) { - chartData[this.positions[symbol][this.keys[0]]].value = chartData[ - this.positions[symbol][this.keys[0]] - ].value.plus(this.positions[symbol].value); + if (this.positions[symbol][this.keys[0]].toUpperCase()) { + if (chartData[this.positions[symbol][this.keys[0]].toUpperCase()]) { + chartData[this.positions[symbol][this.keys[0]].toUpperCase()].value = + chartData[ + this.positions[symbol][this.keys[0]].toUpperCase() + ].value.plus(this.positions[symbol].value); if ( - chartData[this.positions[symbol][this.keys[0]]].subCategory[ - this.positions[symbol][this.keys[1]] - ] + chartData[this.positions[symbol][this.keys[0]].toUpperCase()] + .subCategory[this.positions[symbol][this.keys[1]]] ) { - chartData[this.positions[symbol][this.keys[0]]].subCategory[ - this.positions[symbol][this.keys[1]] - ].value = chartData[ - this.positions[symbol][this.keys[0]] - ].subCategory[this.positions[symbol][this.keys[1]]].value.plus( - this.positions[symbol].value - ); + chartData[ + this.positions[symbol][this.keys[0]].toUpperCase() + ].subCategory[this.positions[symbol][this.keys[1]]].value = + chartData[ + this.positions[symbol][this.keys[0]].toUpperCase() + ].subCategory[this.positions[symbol][this.keys[1]]].value.plus( + this.positions[symbol].value + ); } else { - chartData[this.positions[symbol][this.keys[0]]].subCategory[ - this.positions[symbol][this.keys[1]] ?? UNKNOWN_KEY - ] = { value: new Big(this.positions[symbol].value) }; + chartData[ + this.positions[symbol][this.keys[0]].toUpperCase() + ].subCategory[this.positions[symbol][this.keys[1]] ?? UNKNOWN_KEY] = + { value: new Big(this.positions[symbol].value) }; } } else { - chartData[this.positions[symbol][this.keys[0]]] = { - name: this.positions[symbol].name, + chartData[this.positions[symbol][this.keys[0]].toUpperCase()] = { + name: this.positions[symbol][this.keys[0]], subCategory: {}, value: new Big(this.positions[symbol].value ?? 0) }; if (this.positions[symbol][this.keys[1]]) { - chartData[this.positions[symbol][this.keys[0]]].subCategory = { + chartData[ + this.positions[symbol][this.keys[0]].toUpperCase() + ].subCategory = { [this.positions[symbol][this.keys[1]]]: { value: new Big(this.positions[symbol].value) } @@ -232,8 +236,8 @@ export class PortfolioProportionChartComponent } ]; - let labels = chartDataSorted.map(([label]) => { - return label; + let labels = chartDataSorted.map(([symbol, { name }]) => { + return name; }); if (this.keys[1]) { From bb9415cc153c68790d401b81a6ab7f3988740f56 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 26 May 2023 20:43:09 +0200 Subject: [PATCH 14/18] Release 1.272.0 (#2005) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d716e7c4..2bdd32d85 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 +## 1.272.0 - 2023-05-26 ### Added diff --git a/package.json b/package.json index bac60f0cc..618593dbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "1.271.0", + "version": "1.272.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "scripts": { From 3bc8b3c836a89b9e4394ba89c0461a97e454bc23 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 27 May 2023 09:34:02 +0200 Subject: [PATCH 15/18] Feature/add link to manage benchmarks in benchmark comparator component (#2007) * Add link to manage benchmarks * Update changelog --- CHANGELOG.md | 6 ++ .../admin-overview/admin-overview.html | 13 --- .../benchmark-comparator.component.html | 7 +- .../benchmark-comparator.component.ts | 7 ++ .../benchmark-comparator.module.ts | 4 +- apps/client/src/locales/messages.de.xlf | 96 ++++++++++--------- apps/client/src/locales/messages.es.xlf | 96 ++++++++++--------- apps/client/src/locales/messages.fr.xlf | 96 ++++++++++--------- apps/client/src/locales/messages.it.xlf | 96 ++++++++++--------- apps/client/src/locales/messages.nl.xlf | 96 ++++++++++--------- apps/client/src/locales/messages.pt.xlf | 96 ++++++++++--------- apps/client/src/locales/messages.xlf | 93 +++++++++--------- 12 files changed, 370 insertions(+), 336 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bdd32d85..5153ab476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added a link to manage the benchmarks to the benchmark comparator + ## 1.272.0 - 2023-05-26 ### Added 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 80a285ffd..0f4127e51 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -72,19 +72,6 @@
    -
    -
    Benchmarks
    -
    - - - - -
    {{ benchmark.symbol }}
    -
    -
    Compare with... {{ symbolProfile.name }} + Manage Benchmarks
    diff --git a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts index 9e6cc9be3..9a6bd1d30 100644 --- a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts +++ b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -23,6 +23,7 @@ import { parseDate } from '@ghostfolio/common/helper'; import { LineChartItem, User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { ColorScheme } from '@ghostfolio/common/types'; import { SymbolProfile } from '@prisma/client'; import { @@ -59,6 +60,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy { @ViewChild('chartCanvas') chartCanvas; public chart: Chart<'line'>; + public hasPermissionToAccessAdminControl: boolean; public constructor() { Chart.register( @@ -76,6 +78,11 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy { } public ngOnChanges() { + this.hasPermissionToAccessAdminControl = hasPermission( + this.user?.permissions, + permissions.accessAdminControl + ); + if (this.performanceDataItems) { this.initialize(); } diff --git a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.module.ts b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.module.ts index 23b0a48a1..5280404dd 100644 --- a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.module.ts +++ b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatSelectModule } from '@angular/material/select'; +import { RouterModule } from '@angular/router'; import { GfPremiumIndicatorModule } from '@ghostfolio/ui/premium-indicator'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -16,7 +17,8 @@ import { BenchmarkComparatorComponent } from './benchmark-comparator.component'; GfPremiumIndicatorModule, MatSelectModule, NgxSkeletonLoaderModule, - ReactiveFormsModule + ReactiveFormsModule, + RouterModule ] }) export class GfBenchmarkComparatorModule {} diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 836bca3ae..bb12bf743 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -94,7 +94,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -210,7 +210,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -250,7 +250,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -386,7 +386,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -422,7 +422,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -450,7 +450,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -552,10 +552,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -582,7 +578,7 @@ Systemmeldung apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 @@ -590,7 +586,7 @@ Systemmeldung setzen apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 @@ -598,7 +594,7 @@ Lese-Modus apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 @@ -606,7 +602,7 @@ Gutscheincodes apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 @@ -614,7 +610,7 @@ Hinzufügen apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 @@ -622,7 +618,7 @@ Verwaltung apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 @@ -630,7 +626,7 @@ Cache leeren apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -1134,7 +1130,7 @@ Sektoren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1150,7 +1146,7 @@ Länder apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1162,7 +1158,7 @@ Tags apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1356,6 +1352,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -1626,7 +1626,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2042,7 +2042,7 @@ Kommentar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2058,7 +2058,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2110,7 +2110,7 @@ Portfolio apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -2430,7 +2430,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2446,7 +2446,7 @@ Sektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2458,7 +2458,7 @@ Land apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -2653,20 +2653,12 @@ 253 - - Benchmarks - Benchmarks - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 - - Compare with... Vergleichen mit... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -2674,7 +2666,7 @@ Benchmark apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 + 118 @@ -2918,7 +2910,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -2926,11 +2918,11 @@ Keine Daten verfügbar libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -3046,7 +3038,7 @@ Symbol Zuordnung apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -3078,7 +3070,7 @@ Benutzer Registrierung apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -3608,10 +3600,6 @@ Gather Historical Data Historische Daten herunterladen - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3813,6 +3801,22 @@ 14 + + Set as Benchmark + Als Benchmark setzen + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + + + Manage Benchmarks + Benchmarks verwalten + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 4f602cfb5..7f9533d77 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -95,7 +95,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -211,7 +211,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -251,7 +251,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -387,7 +387,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -423,7 +423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -451,7 +451,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -553,10 +553,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -583,7 +579,7 @@ Mensaje del sistema apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 @@ -591,7 +587,7 @@ Establecer mensaje apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 @@ -599,7 +595,7 @@ Modo de solo lectura apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 @@ -607,7 +603,7 @@ Cupones apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 @@ -615,7 +611,7 @@ Añadir apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 @@ -623,7 +619,7 @@ Tareas domésticas apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 @@ -631,7 +627,7 @@ Limpiar caché apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -1135,7 +1131,7 @@ Sectores apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1151,7 +1147,7 @@ Países apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1163,7 +1159,7 @@ Etiquetas apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1357,6 +1353,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -1627,7 +1627,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2043,7 +2043,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2059,7 +2059,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2111,7 +2111,7 @@ Cartera apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -2411,7 +2411,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2467,7 +2467,7 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2479,7 +2479,7 @@ País apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -2659,15 +2659,7 @@ Benchmark apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 - - - - Benchmarks - Benchmark - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 + 118 @@ -2675,7 +2667,7 @@ Comparar con... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -2919,7 +2911,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -2927,11 +2919,11 @@ Sin datos disponibles libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -3047,7 +3039,7 @@ Mapeo de símbolos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -3079,7 +3071,7 @@ User Signup apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -3601,10 +3593,6 @@ Gather Historical Data Gather Historical Data - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3814,6 +3802,22 @@ 14 + + Set as Benchmark + Set as Benchmark + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + + + Manage Benchmarks + Manage Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 467ded612..2d80790a8 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -118,7 +118,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -186,7 +186,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -274,7 +274,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -306,7 +306,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -450,7 +450,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -486,7 +486,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -522,7 +522,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -542,7 +542,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -562,7 +562,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -624,10 +624,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -646,7 +642,7 @@ Secteur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -658,7 +654,7 @@ Pays apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -674,7 +670,7 @@ Secteurs apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -690,7 +686,7 @@ Pays apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -702,7 +698,7 @@ Équivalence de Symboles apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -710,7 +706,7 @@ Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -797,20 +793,12 @@ 70 - - Benchmarks - Références - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 - - Tags Étiquettes apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -826,7 +814,7 @@ Inscription de Nouveaux Utilisateurs apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -834,7 +822,7 @@ Mode Lecture Seule apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 @@ -842,7 +830,7 @@ Message Système apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 @@ -850,7 +838,7 @@ Définir Message apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 @@ -858,7 +846,7 @@ Codes promotionnels apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 @@ -866,7 +854,7 @@ Ajouter apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 @@ -874,7 +862,7 @@ Maintenance apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 @@ -882,7 +870,7 @@ Vider le Cache apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -974,7 +962,7 @@ Comparer avec... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -982,7 +970,7 @@ Portefeuille apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -994,7 +982,7 @@ Référence apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 + 118 @@ -2108,6 +2096,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -2961,7 +2953,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -3145,11 +3137,11 @@ Pas de données disponibles libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -3599,10 +3591,6 @@ Gather Historical Data Gather Historical Data - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3812,6 +3800,22 @@ 14 + + Set as Benchmark + Set as Benchmark + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + + + Manage Benchmarks + Manage Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index c978a04f4..43fd65372 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -95,7 +95,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -211,7 +211,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -251,7 +251,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -387,7 +387,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -423,7 +423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -451,7 +451,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -553,10 +553,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -583,7 +579,7 @@ Messaggio di sistema apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 @@ -591,7 +587,7 @@ Imposta messaggio apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 @@ -599,7 +595,7 @@ Modalità di sola lettura apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 @@ -607,7 +603,7 @@ Buoni sconto apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 @@ -615,7 +611,7 @@ Aggiungi apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 @@ -623,7 +619,7 @@ Bilancio domestico apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 @@ -631,7 +627,7 @@ Svuota la cache apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -1135,7 +1131,7 @@ Settori apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1151,7 +1147,7 @@ Paesi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1163,7 +1159,7 @@ Tag apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1357,6 +1353,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -1627,7 +1627,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2043,7 +2043,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2059,7 +2059,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2111,7 +2111,7 @@ Portafoglio apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -2411,7 +2411,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2467,7 +2467,7 @@ Settore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2479,7 +2479,7 @@ Paese apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -2659,15 +2659,7 @@ Benchmark apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 - - - - Benchmarks - Benchmark - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 + 118 @@ -2675,7 +2667,7 @@ Confronta con... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -2919,7 +2911,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -2927,11 +2919,11 @@ No data available libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -3047,7 +3039,7 @@ Symbol Mapping apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -3079,7 +3071,7 @@ User Signup apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -3601,10 +3593,6 @@ Gather Historical Data Gather Historical Data - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3814,6 +3802,22 @@ 14 + + Set as Benchmark + Set as Benchmark + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + + + Manage Benchmarks + Manage Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index e7f592aea..65868a700 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -94,7 +94,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -210,7 +210,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -250,7 +250,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -386,7 +386,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -422,7 +422,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -450,7 +450,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -552,10 +552,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -582,7 +578,7 @@ Systeembericht apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 @@ -590,7 +586,7 @@ Bericht instellen apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 @@ -598,7 +594,7 @@ Alleen lezen apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 @@ -606,7 +602,7 @@ Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 @@ -614,7 +610,7 @@ Toevoegen apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 @@ -622,7 +618,7 @@ Huishouding apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 @@ -630,7 +626,7 @@ Cache legen apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -1134,7 +1130,7 @@ Sectoren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1150,7 +1146,7 @@ Landen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1162,7 +1158,7 @@ Tags apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1356,6 +1352,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -1626,7 +1626,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2042,7 +2042,7 @@ Opmerking apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2058,7 +2058,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2110,7 +2110,7 @@ Portefeuille apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -2410,7 +2410,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2466,7 +2466,7 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2478,7 +2478,7 @@ Land apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -2658,15 +2658,7 @@ Benchmark apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 - - - - Benchmarks - Benchmarks - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 + 118 @@ -2674,7 +2666,7 @@ Vergelijk met... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -2918,7 +2910,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -2926,11 +2918,11 @@ Geen gegevens beschikbaar libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -3046,7 +3038,7 @@ Symbool toewijzen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -3078,7 +3070,7 @@ Account aanmaken apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -3608,10 +3600,6 @@ Gather Historical Data Gather Historical Data - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3813,6 +3801,22 @@ 14 + + Set as Benchmark + Set as Benchmark + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + + + Manage Benchmarks + Manage Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 36fe7bc78..39b679157 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -118,7 +118,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -186,7 +186,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -274,7 +274,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -306,7 +306,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -450,7 +450,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -486,7 +486,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -522,7 +522,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -542,7 +542,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -562,7 +562,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -624,10 +624,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -705,20 +701,12 @@ 70 - - Benchmarks - Benchmarks - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 - - System Message System Message apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 @@ -726,7 +714,7 @@ Set Message apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 @@ -734,7 +722,7 @@ Read-only Mode apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 @@ -742,7 +730,7 @@ Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 @@ -750,7 +738,7 @@ Add apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 @@ -758,7 +746,7 @@ Housekeeping apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 @@ -766,7 +754,7 @@ Flush Cache apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -858,7 +846,7 @@ Compare with... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -866,7 +854,7 @@ Portfolio apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -878,7 +866,7 @@ Benchmark apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 + 118 @@ -1458,7 +1446,7 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1470,7 +1458,7 @@ Country apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -1486,7 +1474,7 @@ Sectors apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1502,7 +1490,7 @@ Countries apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1514,7 +1502,7 @@ Tags apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2052,6 +2040,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -2210,7 +2202,7 @@ Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2846,7 +2838,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -3022,11 +3014,11 @@ No data available libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -3050,7 +3042,7 @@ Symbol Mapping apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -3058,7 +3050,7 @@ User Signup apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -3600,10 +3592,6 @@ Gather Historical Data Gather Historical Data - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3813,6 +3801,22 @@ 14 + + Set as Benchmark + Set as Benchmark + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + + + Manage Benchmarks + Manage Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 96322b005..f0180872e 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -87,7 +87,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 81 + 88 apps/client/src/app/components/admin-users/admin-users.html @@ -198,7 +198,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 163 + 151 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -235,7 +235,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 57 + 64 @@ -357,7 +357,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 173 + 180 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -392,7 +392,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 180 + 187 apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html @@ -419,7 +419,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 72 + 79 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -509,10 +509,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 132 - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 156 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 38 @@ -536,49 +532,49 @@ System Message apps/client/src/app/components/admin-overview/admin-overview.html - 122 + 109 Set Message apps/client/src/app/components/admin-overview/admin-overview.html - 144 + 131 Read-only Mode apps/client/src/app/components/admin-overview/admin-overview.html - 112 + 99 Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 152 + 139 Add apps/client/src/app/components/admin-overview/admin-overview.html - 194 + 181 Housekeeping apps/client/src/app/components/admin-overview/admin-overview.html - 201 + 188 Flush Cache apps/client/src/app/components/admin-overview/admin-overview.html - 205 + 192 @@ -1033,7 +1029,7 @@ Sectors apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 125 + 132 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1048,7 +1044,7 @@ Countries apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 135 + 142 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1059,7 +1055,7 @@ Tags apps/client/src/app/components/admin-overview/admin-overview.html - 92 + 79 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1238,6 +1234,10 @@ apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html 245 + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 231 + apps/client/src/app/pages/blog/blog-page.html 4 @@ -1476,7 +1476,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 62 + 69 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1853,7 +1853,7 @@ Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 160 + 167 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1868,7 +1868,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 86 + 93 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -1915,7 +1915,7 @@ Portfolio apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 102 + 109 apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -2182,7 +2182,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 95 + 102 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2233,7 +2233,7 @@ Sector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 110 + 117 apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -2244,7 +2244,7 @@ Country apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 119 + 126 apps/client/src/app/components/admin-users/admin-users.html @@ -2405,21 +2405,14 @@ Benchmark apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts - 111 - - - - Benchmarks - - apps/client/src/app/components/admin-overview/admin-overview.html - 79 + 118 Compare with... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html - 18 + 17 @@ -2622,11 +2615,11 @@ No data available libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 371 + 375 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 384 + 388 @@ -2644,7 +2637,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 369 + 373 @@ -2740,7 +2733,7 @@ Symbol Mapping apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 149 + 156 @@ -2775,7 +2768,7 @@ User Signup apps/client/src/app/components/admin-overview/admin-overview.html - 102 + 89 @@ -3252,10 +3245,6 @@ Gather Historical Data - - apps/client/src/app/components/admin-market-data/admin-market-data.html - 150 - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 30 @@ -3434,6 +3423,20 @@ 14 + + Manage Benchmarks + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 34 + + + + Set as Benchmark + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 45 + + From 21ebaae6ef8b6bb99e805683057d1b6aff917659 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 27 May 2023 09:47:58 +0200 Subject: [PATCH 16/18] Add Cloud vs. Self-hosted (#2010) --- .github/ISSUE_TEMPLATE/bug_report.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ffee37bee..22a2ca789 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -36,6 +36,9 @@ The Issue tracker is **ONLY** used for reporting bugs. New features should be di +- [ ] Cloud +- [ ] Self-hosted + - Ghostfolio Version X.Y.Z - Browser - OS From 7529a7a26cbbe88561039e678ecb1ea13ac8282c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 27 May 2023 09:53:48 +0200 Subject: [PATCH 17/18] Feature/support localized routes (#2009) * Support localized routes * Update changelog --- CHANGELOG.md | 1 + apps/client/src/app/app-routing.module.ts | 70 +++++++++--------- apps/client/src/assets/robots.txt | 13 ++++ apps/client/src/assets/sitemap.xml | 90 +++++++++++++++-------- 4 files changed, 111 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5153ab476..863df020b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added a link to manage the benchmarks to the benchmark comparator +- Added support for localized routes ## 1.272.0 - 2023-05-26 diff --git a/apps/client/src/app/app-routing.module.ts b/apps/client/src/app/app-routing.module.ts index b4b2792b8..e824862f7 100644 --- a/apps/client/src/app/app-routing.module.ts +++ b/apps/client/src/app/app-routing.module.ts @@ -5,25 +5,27 @@ import { PageTitleStrategy } from '@ghostfolio/client/services/page-title.strate import { ModulePreloadService } from './core/module-preload.service'; const routes: Routes = [ - { - path: 'about', + ...['about', 'ueber-uns'].map((path) => ({ + path, loadChildren: () => import('./pages/about/about-page.module').then((m) => m.AboutPageModule) - }, - { - path: 'about/changelog', + })), + ...['about/changelog', 'ueber-uns/changelog'].map((path) => ({ + path, loadChildren: () => import('./pages/about/changelog/changelog-page.module').then( (m) => m.ChangelogPageModule ) - }, - { - path: 'about/privacy-policy', - loadChildren: () => - import('./pages/about/privacy-policy/privacy-policy-page.module').then( - (m) => m.PrivacyPolicyPageModule - ) - }, + })), + ...['about/privacy-policy', 'ueber-uns/datenschutzbestimmungen'].map( + (path) => ({ + path, + loadChildren: () => + import('./pages/about/privacy-policy/privacy-policy-page.module').then( + (m) => m.PrivacyPolicyPageModule + ) + }) + ), { path: 'account', loadChildren: () => @@ -48,11 +50,11 @@ const routes: Routes = [ loadChildren: () => import('./pages/auth/auth-page.module').then((m) => m.AuthPageModule) }, - { - path: 'blog', + ...['blog'].map((path) => ({ + path, loadChildren: () => import('./pages/blog/blog-page.module').then((m) => m.BlogPageModule) - }, + })), { path: 'blog/2021/07/hallo-ghostfolio', loadChildren: () => @@ -149,30 +151,30 @@ const routes: Routes = [ loadChildren: () => import('./pages/demo/demo-page.module').then((m) => m.DemoPageModule) }, - { - path: 'faq', + ...['faq', 'haeufig-gestellte-fragen'].map((path) => ({ + path, loadChildren: () => import('./pages/faq/faq-page.module').then((m) => m.FaqPageModule) - }, - { - path: 'features', + })), + ...['features'].map((path) => ({ + path, loadChildren: () => import('./pages/features/features-page.module').then( (m) => m.FeaturesPageModule ) - }, + })), { path: 'home', loadChildren: () => import('./pages/home/home-page.module').then((m) => m.HomePageModule) }, - { - path: 'markets', + ...['markets', 'maerkte'].map((path) => ({ + path, loadChildren: () => import('./pages/markets/markets-page.module').then( (m) => m.MarketsPageModule ) - }, + })), { path: 'open', loadChildren: () => @@ -192,27 +194,27 @@ const routes: Routes = [ (m) => m.PortfolioPageModule ) }, - { - path: 'pricing', + ...['pricing', 'preise'].map((path) => ({ + path, loadChildren: () => import('./pages/pricing/pricing-page.module').then( (m) => m.PricingPageModule ) - }, - { - path: 'register', + })), + ...['register', 'registrierung'].map((path) => ({ + path, loadChildren: () => import('./pages/register/register-page.module').then( (m) => m.RegisterPageModule ) - }, - { - path: 'resources', + })), + ...['resources', 'ressourcen'].map((path) => ({ + path, loadChildren: () => import('./pages/resources/resources-page.module').then( (m) => m.ResourcesPageModule ) - }, + })), { path: 'start', loadChildren: () => diff --git a/apps/client/src/assets/robots.txt b/apps/client/src/assets/robots.txt index 059aea258..3b0250e72 100644 --- a/apps/client/src/assets/robots.txt +++ b/apps/client/src/assets/robots.txt @@ -1,6 +1,19 @@ User-agent: * Allow: / +Disallow: /de/about/* +Disallow: /de/faq +Disallow: /de/markets +Disallow: /de/portfolio/* +Disallow: /de/pricing +Disallow: /de/register +Disallow: /de/resources +Disallow: /de/ueber-uns/datenschutzbestimmungen Disallow: /en/about/privacy-policy Disallow: /en/p/* +Disallow: /en/portfolio/* +Disallow: /portfolio/* +Disallow: /pricing/* +Disallow: /register/* +Disallow: /resources/* Sitemap: https://ghostfol.io/sitemap.xml diff --git a/apps/client/src/assets/sitemap.xml b/apps/client/src/assets/sitemap.xml index 8e4f8725e..98d5bf777 100644 --- a/apps/client/src/assets/sitemap.xml +++ b/apps/client/src/assets/sitemap.xml @@ -6,110 +6,142 @@ http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"> https://ghostfol.io - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/de/blog - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/de/blog/2021/07/hallo-ghostfolio - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 - - https://ghostfol.io/de/pricing - 2023-05-20T00:00:00+00:00 + + https://ghostfol.io/de/features + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/haeufig-gestellte-fragen + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/maerkte + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/open + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/preise + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/registrierung + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/ressourcen + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/ueber-uns + 2023-05-27T00:00:00+00:00 + + + https://ghostfol.io/de/ueber-uns/changelog + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/about - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/about/changelog - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2021/07/hello-ghostfolio - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/01/ghostfolio-first-months-in-open-source - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/07/ghostfolio-meets-internet-identity - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/07/how-do-i-get-my-finances-in-order - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/08/500-stars-on-github - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/10/hacktoberfest-2022 - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/11/black-friday-2022 - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2022/12/the-importance-of-tracking-your-personal-finances - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2023/02/ghostfolio-meets-umbrel - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2023/03/ghostfolio-reaches-1000-stars-on-github - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/blog/2023/05/unlock-your-financial-potential-with-ghostfolio - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/demo - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/faq - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/features - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/markets - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/open - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/pricing - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/register - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 https://ghostfol.io/en/resources - 2023-05-20T00:00:00+00:00 + 2023-05-27T00:00:00+00:00 From 19333ab084fa537e6a0c2f4fdfc09dae4a773e7b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 27 May 2023 10:48:10 +0200 Subject: [PATCH 18/18] Fix warnings (#2011) --- .../src/app/benchmark/benchmark.controller.ts | 2 +- .../data-provider/data-provider.service.ts | 3 +- ...benchmark-market-data-details.interface.ts | 2 +- libs/common/src/lib/interfaces/index.ts | 86 +++++++++---------- .../responses/benchmark-response.interface.ts | 2 +- libs/common/src/lib/types/index.ts | 16 ++-- 6 files changed, 55 insertions(+), 56 deletions(-) diff --git a/apps/api/src/app/benchmark/benchmark.controller.ts b/apps/api/src/app/benchmark/benchmark.controller.ts index 91426090e..d59a231ff 100644 --- a/apps/api/src/app/benchmark/benchmark.controller.ts +++ b/apps/api/src/app/benchmark/benchmark.controller.ts @@ -1,6 +1,6 @@ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor'; -import { +import type { BenchmarkMarketDataDetails, BenchmarkResponse, UniqueAsset diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 387c71be2..c05fc3e4f 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -11,8 +11,7 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PROPERTY_DATA_SOURCE_MAPPING } from '@ghostfolio/common/config'; import { DATE_FORMAT, getStartOfUtcDate } from '@ghostfolio/common/helper'; -import { UserWithSettings } from '@ghostfolio/common/types'; -import { Granularity } from '@ghostfolio/common/types'; +import type { Granularity, UserWithSettings } from '@ghostfolio/common/types'; import { Inject, Injectable, Logger } from '@nestjs/common'; import { DataSource, MarketData, SymbolProfile } from '@prisma/client'; import { format, isValid } from 'date-fns'; diff --git a/libs/common/src/lib/interfaces/benchmark-market-data-details.interface.ts b/libs/common/src/lib/interfaces/benchmark-market-data-details.interface.ts index 10fdeff32..ed693b9af 100644 --- a/libs/common/src/lib/interfaces/benchmark-market-data-details.interface.ts +++ b/libs/common/src/lib/interfaces/benchmark-market-data-details.interface.ts @@ -1,4 +1,4 @@ -import { LineChartItem } from './line-chart-item.interface'; +import { LineChartItem } from '@ghostfolio/common/interfaces'; export interface BenchmarkMarketDataDetails { marketData: LineChartItem[]; diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index 538615861..93268153b 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -1,49 +1,49 @@ -import { Access } from './access.interface'; -import { Accounts } from './accounts.interface'; -import { AdminData } from './admin-data.interface'; -import { AdminJobs } from './admin-jobs.interface'; -import { AdminMarketDataDetails } from './admin-market-data-details.interface'; -import { +import type { Access } from './access.interface'; +import type { Accounts } from './accounts.interface'; +import type { AdminData } from './admin-data.interface'; +import type { AdminJobs } from './admin-jobs.interface'; +import type { AdminMarketDataDetails } from './admin-market-data-details.interface'; +import type { AdminMarketData, AdminMarketDataItem } from './admin-market-data.interface'; -import { BenchmarkMarketDataDetails } from './benchmark-market-data-details.interface'; -import { BenchmarkProperty } from './benchmark-property.interface'; -import { Benchmark } from './benchmark.interface'; -import { Coupon } from './coupon.interface'; -import { DataProviderInfo } from './data-provider-info.interface'; -import { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface'; -import { Export } from './export.interface'; -import { FilterGroup } from './filter-group.interface'; -import { Filter } from './filter.interface'; -import { HistoricalDataItem } from './historical-data-item.interface'; -import { InfoItem } from './info-item.interface'; -import { LineChartItem } from './line-chart-item.interface'; -import { PortfolioChart } from './portfolio-chart.interface'; -import { PortfolioDetails } from './portfolio-details.interface'; -import { PortfolioDividends } from './portfolio-dividends.interface'; -import { PortfolioInvestments } from './portfolio-investments.interface'; -import { PortfolioItem } from './portfolio-item.interface'; -import { PortfolioOverview } from './portfolio-overview.interface'; -import { PortfolioPerformance } from './portfolio-performance.interface'; -import { PortfolioPosition } from './portfolio-position.interface'; -import { PortfolioPublicDetails } from './portfolio-public-details.interface'; -import { PortfolioReportRule } from './portfolio-report-rule.interface'; -import { PortfolioReport } from './portfolio-report.interface'; -import { PortfolioSummary } from './portfolio-summary.interface'; -import { Position } from './position.interface'; -import { BenchmarkResponse } from './responses/benchmark-response.interface'; -import { ResponseError } from './responses/errors.interface'; -import { ImportResponse } from './responses/import-response.interface'; -import { OAuthResponse } from './responses/oauth-response.interface'; -import { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface'; -import { ScraperConfiguration } from './scraper-configuration.interface'; -import { Statistics } from './statistics.interface'; -import { Subscription } from './subscription.interface'; -import { TimelinePosition } from './timeline-position.interface'; -import { UniqueAsset } from './unique-asset.interface'; -import { UserSettings } from './user-settings.interface'; -import { User } from './user.interface'; +import type { BenchmarkMarketDataDetails } from './benchmark-market-data-details.interface'; +import type { BenchmarkProperty } from './benchmark-property.interface'; +import type { Benchmark } from './benchmark.interface'; +import type { Coupon } from './coupon.interface'; +import type { DataProviderInfo } from './data-provider-info.interface'; +import type { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface'; +import type { Export } from './export.interface'; +import type { FilterGroup } from './filter-group.interface'; +import type { Filter } from './filter.interface'; +import type { HistoricalDataItem } from './historical-data-item.interface'; +import type { InfoItem } from './info-item.interface'; +import type { LineChartItem } from './line-chart-item.interface'; +import type { PortfolioChart } from './portfolio-chart.interface'; +import type { PortfolioDetails } from './portfolio-details.interface'; +import type { PortfolioDividends } from './portfolio-dividends.interface'; +import type { PortfolioInvestments } from './portfolio-investments.interface'; +import type { PortfolioItem } from './portfolio-item.interface'; +import type { PortfolioOverview } from './portfolio-overview.interface'; +import type { PortfolioPerformance } from './portfolio-performance.interface'; +import type { PortfolioPosition } from './portfolio-position.interface'; +import type { PortfolioPublicDetails } from './portfolio-public-details.interface'; +import type { PortfolioReportRule } from './portfolio-report-rule.interface'; +import type { PortfolioReport } from './portfolio-report.interface'; +import type { PortfolioSummary } from './portfolio-summary.interface'; +import type { Position } from './position.interface'; +import type { BenchmarkResponse } from './responses/benchmark-response.interface'; +import type { ResponseError } from './responses/errors.interface'; +import type { ImportResponse } from './responses/import-response.interface'; +import type { OAuthResponse } from './responses/oauth-response.interface'; +import type { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface'; +import type { ScraperConfiguration } from './scraper-configuration.interface'; +import type { Statistics } from './statistics.interface'; +import type { Subscription } from './subscription.interface'; +import type { TimelinePosition } from './timeline-position.interface'; +import type { UniqueAsset } from './unique-asset.interface'; +import type { UserSettings } from './user-settings.interface'; +import type { User } from './user.interface'; export { Access, diff --git a/libs/common/src/lib/interfaces/responses/benchmark-response.interface.ts b/libs/common/src/lib/interfaces/responses/benchmark-response.interface.ts index 262d55fba..d47cf1864 100644 --- a/libs/common/src/lib/interfaces/responses/benchmark-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/benchmark-response.interface.ts @@ -1,4 +1,4 @@ -import { Benchmark } from '../benchmark.interface'; +import { Benchmark } from '@ghostfolio/common/interfaces'; export interface BenchmarkResponse { benchmarks: Benchmark[]; diff --git a/libs/common/src/lib/types/index.ts b/libs/common/src/lib/types/index.ts index 258ce211d..dc6f154dc 100644 --- a/libs/common/src/lib/types/index.ts +++ b/libs/common/src/lib/types/index.ts @@ -1,17 +1,17 @@ import type { AccessWithGranteeUser } from './access-with-grantee-user.type'; -import { AccountWithPlatform } from './account-with-platform.type'; -import { AccountWithValue } from './account-with-value.type'; +import type { AccountWithPlatform } from './account-with-platform.type'; +import type { AccountWithValue } from './account-with-value.type'; import type { ColorScheme } from './color-scheme.type'; import type { DateRange } from './date-range.type'; import type { Granularity } from './granularity.type'; -import { GroupBy } from './group-by.type'; -import { MarketState } from './market-state.type'; -import { Market } from './market.type'; +import type { GroupBy } from './group-by.type'; +import type { MarketState } from './market-state.type'; +import type { Market } from './market.type'; import type { OrderWithAccount } from './order-with-account.type'; import type { RequestWithUser } from './request-with-user.type'; -import { SubscriptionOffer } from './subscription-offer.type'; -import { ToggleOption } from './toggle-option.type'; -import { UserWithSettings } from './user-with-settings.type'; +import type { SubscriptionOffer } from './subscription-offer.type'; +import type { ToggleOption } from './toggle-option.type'; +import type { UserWithSettings } from './user-with-settings.type'; import type { ViewMode } from './view-mode.type'; export type {